Difference between revisions of "DIP22"

From D Wiki
Jump to: navigation, search
m (internal is internal)
Line 7: Line 7:
 
|-
 
|-
 
|Version:
 
|Version:
|1
+
|2
 
|-
 
|-
 
|Status:
 
|Status:
Line 16: Line 16:
 
|-
 
|-
 
|Last Modified:
 
|Last Modified:
|2013-01-28
+
|2013-02-04
 
|-
 
|-
 
|Author:
 
|Author:
Line 25: Line 25:
 
|}
 
|}
  
== Abstract ==
+
== Changelog ==
There are two important issues with current protection attribute design:
+
 
 +
=== Version 2 ===
  
* Senseless name clashes between '''private''' and '''public''' symbols
+
* Proposals related to internal linkage separated to another DIP
* No way to specify internal linkage storage class
+
* Added .tupleof to trait-like exclusions
 +
* Removed proposal to change an error message
  
This DIP addresses both of them with two decoupled proposals:
+
== Abstract ==
* Change of '''private''' related name resolution rules
+
This proposal attempts to solve one of important issues with current protection attribute design: senseless name clashes between '''private''' and '''public''' symbols. So change of '''private''' related name resolution rules is proposed.
* Definition of '''static''' storage class for module-scope symbols.
 
  
 
== Rationale ==
 
== Rationale ==
  
=== private is private ===
+
'''private''' is an encapsulation tool. If it is not intended to be used by "outsiders", it should not interfere with them at all. It creates no new limitations and reduces amount of code breakage by changes in other modules.
'''private''' is an encapsulation tool. If it is not intended to be used by "outsiders", it should not be shown to them at all. It creates no new limitations and reduces amount of code breakage by changes in other modules.
 
 
 
=== static is internal ===
 
If '''private''' is a source code level encapsulation tool then '''static''' is object file / binary level encapsulation tool. It allows even more struct separation of implementation-specific code and cleans up object files from unneeded symbols, providing more freedom for compiler optimizations.
 
  
 
== Description ==
 
== Description ==
 
=== private-related changes ===
 
  
 
* All changes are same for both classes and modules: it breaks no code but leaves consistent approach.
 
* All changes are same for both classes and modules: it breaks no code but leaves consistent approach.
* Compiler errors upon access to '''private''' symbol are changed from ''"%s is not accessible"'' to ''"undefined identifier %s"''
+
* Private symbol look-up with no overloads in action stays the same: error message about access.
 
* Overload resolution takes place after protection attribute questions are settled. '''private''' symbols do not take part in overload resolution.
 
* Overload resolution takes place after protection attribute questions are settled. '''private''' symbols do not take part in overload resolution.
 
* As privates are already non-virtual, override resolution does not need to change in this regard.
 
* As privates are already non-virtual, override resolution does not need to change in this regard.
* All <code>__traits</code> still show private symbols. Those are advanced user tools and having this may be essential to library code.
+
* All <code>__traits</code> still show private symbols. Those are advanced user tools and having this may be essential to library code. Same goes for access via .tupleof.
 
 
=== new meaning for static ===
 
 
 
Currently static storage class is no-op for global symbols. It is a big luck as we can use it in the way similar to plain C:
 
 
 
* All global static symbols are implicitly private
 
* It is forbidden to leak static symbols outside of the module, i.e.
 
<syntaxhighlight lang="D">
 
static struct Internal { }
 
void func1(Internal) { } // compile error
 
private void func2(Internal) { } // compile error, private still leaks its symbols to object file
 
void func3() { Internal t; } // fine, does not leak to func3 signature
 
alias Internal External; // compile error
 
static alias Internal InternalPrim; // fine
 
</syntaxhighlight>
 
* As can have just been seen, nested symbols can also be marked as '''static''' in case there were already static entities: enums, structs, classes, aliases. Variables and functions already have '''static''' defined for other usaged
 
* No '''static''' symbols can be found in resulting object file. They are not shown in traits like <code>__traits(allMembers)</code>. From the point of view of other modules they simply do not exist and may be all inlined or optimized away or whatever.
 
* Only module-level symbols can be marked with global '''static''', for example, nested struct types can't. It is minor limitation that greatly simplifies interaction with other language features like <code>alias this</code>.
 
  
 
=== other protection attribute changes ===
 
=== other protection attribute changes ===
Line 76: Line 53:
 
* '''package''' matches '''private''' changes from the point of view of other packages
 
* '''package''' matches '''private''' changes from the point of view of other packages
 
* '''extern''' stays the same
 
* '''extern''' stays the same
* '''protected''' matches '''private''' changes, descendant still treat protected symbols as '''public''' ones. It is a rare guest in idiomatic D code but does no harm and may be useful for transition from other languages.
+
* '''protected''' matches '''private''' changes, descendants still treat protected symbols as '''public''' ones. It is a rare guest in idiomatic D code but does no harm and may be useful for transition from other languages.
  
 
=== other name resolution changes ===
 
=== other name resolution changes ===
Line 85: Line 62:
 
== Possible code breakage and solutions ==
 
== Possible code breakage and solutions ==
  
* global '''static''' had no meaning before and should not have been used like that. It may happen that is used by accident or in generic code gen. To be absolutely sure this brings no surprises I suggest to create a dmd option that will find and print all usages of '''static''' in global context. It should appear in a release _before_ this DIP release and kept for one release after, then removed.
+
No previously valid code will become illegal in normal use cases, as this proposal is more permissive than current behavior. As __traits and .tupleof will still work for '''private''' as before, any library that relies on them should not break.
 
 
* '''private''' simply replaces one error with another and allows new legal code. Code breakage very unlikely.
 
 
 
* as __traits will still work for '''private''' as before, any library that relies on them should not break
 
  
 
== Walters concerns ==
 
== Walters concerns ==
Line 107: Line 80:
 
2. ''at class scope''
 
2. ''at class scope''
  
D minimal encapsulation unit is module. '''Private''' class members are, technically, '''private''' module members and thus have the same behavior. Same for '''package''' and '''public'''. '''Protected''' is only special case that takes additional parameter into consideration.
+
D minimal encapsulation unit is a module. '''Private''' class members are, technically, '''private''' module members and thus have the same behavior. Same for '''package''' and '''public'''. '''Protected''' is only special case that takes additional parameter into consideration.
  
 
3. ''at template mixin scope''
 
3. ''at template mixin scope''

Revision as of 14:58, 4 February 2013

Title: Private symbol visibility
DIP: 22
Version: 2
Status: Draft
Created: 2013-01-28
Last Modified: 2013-02-04
Author: Михаил Страшун (m.strashun gmail.com) (Dicebot)
Links: Access specifiers and visibility : data gathered before creating proposal

Changelog

Version 2

  • Proposals related to internal linkage separated to another DIP
  • Added .tupleof to trait-like exclusions
  • Removed proposal to change an error message

Abstract

This proposal attempts to solve one of important issues with current protection attribute design: senseless name clashes between private and public symbols. So change of private related name resolution rules is proposed.

Rationale

private is an encapsulation tool. If it is not intended to be used by "outsiders", it should not interfere with them at all. It creates no new limitations and reduces amount of code breakage by changes in other modules.

Description

  • All changes are same for both classes and modules: it breaks no code but leaves consistent approach.
  • Private symbol look-up with no overloads in action stays the same: error message about access.
  • Overload resolution takes place after protection attribute questions are settled. private symbols do not take part in overload resolution.
  • As privates are already non-virtual, override resolution does not need to change in this regard.
  • All __traits still show private symbols. Those are advanced user tools and having this may be essential to library code. Same goes for access via .tupleof.

other protection attribute changes

  • public stays the same
  • package matches private changes from the point of view of other packages
  • extern stays the same
  • protected matches private changes, descendants still treat protected symbols as public ones. It is a rare guest in idiomatic D code but does no harm and may be useful for transition from other languages.

other name resolution changes

  • UFCS functions should also take priority over private class functions when names conflict
  • alias this protection attribute overrides protection attribute of aliased symbol ( not transitive )

Possible code breakage and solutions

No previously valid code will become illegal in normal use cases, as this proposal is more permissive than current behavior. As __traits and .tupleof will still work for private as before, any library that relies on them should not break.

Walters concerns

original comment

1. what access means at module scope

"Does this symbol is ignored when doing symbol name look-up?". All protection attributes boil down to simple answer (Yes/No) depending on symbol origins and place look-up is made from. In example:

Symbol origin:               module a;
Look-up origin:              not module a;
Symbol protection attribute: private
Answer:                      No

2. at class scope

D minimal encapsulation unit is a module. Private class members are, technically, private module members and thus have the same behavior. Same for package and public. Protected is only special case that takes additional parameter into consideration.

3. at template mixin scope

No changes here. For templates look-up origin is definition module. For mixin templates - instantiation module. Other than that, usual rules apply.

4. backwards compatibility

See "Possible code breakage and solutions"

5. overloading at each scope level and the interactions with access

See "Description".

6. I'd also throw in getting rid of the "protected" access attribute completely, as I've seen debate over that being a useless idea

I have found no harm in keeping it. This will break code for sure and is irrelevant to this DIP topic.

7. there's also some debate about what "package" should mean

This is also irrelevant to this DIP. While there may be debates on meaning of package concept, meaning of package protection attribute is solid: encapsulation within set of modules belonging to same package, whatever they are.

Copyright

This document has been placed in the Public Domain.