-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
private
vs public
*syntax* strategy, as well as other visibility tools like external
/api
/etc.
#665
Comments
Similar to the switch from an API file to an implementation file allowing reliably detecting a missing annotation, we could have a language feature for a common practice in C++ of a comment in the class (or file) of a comment that says "implementation details only below". This would basically be a syntax that would preclude declaring new public APIs afterward, insisting that anything either match an already declared public API (perhaps to define it) or be annotated in some non-public way. (Credit to @geoffromer in part for suggesting this pattern.) |
I find this argument to be compelling. I'm convinced we should annotate access locally, with the absence of an annotation for the public interface and an explicit |
Confirmed with @KateGregory as well so closing as resolved. (Still needs to be incorporated into a proposal at some point.) |
…ork (#561) This proposal defines the very basics of `class` types, primarily focused on: - use cases including: data classes, encapsulated types, inheritance with and without `virtual`, interfaces as base classes, and mixins for code reuse; - anonymous data types for called _structural data classes_ or _struct types_. Struct literals are used to initialize class values and ad-hoc parameter and return types with named components; and - future work, including the provisional syntax already in use for features that have not been decided. The intent is to both make some small incremental progress and get agreement on direction. As such it doesn't include things like nominal types, methods, access control, inheritance, etc. It proposes this struct type and literal syntax: ``` var p: {.x: Int, .y: Int} = {.x = 0, .y = 1}; ``` Note that it uses commas (`,`) between fields instead of semicolons (`;`), and no introducer for types or literal values. Incorporates decisions from #665 , #653 , #651 Co-authored-by: Geoff Romer <gromer@google.com> Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Reopening per this discussion on #752 ("api file default public"). We'd like clarification on two scenarios:
|
I've been trying to recall this discussion, and I think my memory is somewhat partial... but also the discussion may not have completed. Anyways, writing down what I have in my head so it isn't lost. =D We didn't discuss the first point around redeclarations of methods that I recall. We did discuss the But maybe this isn't as bad as imagined? If all the uses of the function use the publicly declared name, the typo'ed definition would be diagnosed as unused. Any uses of the publicly declared name would eventually be diagnosed as not having a definition. And if by some chance every use finds the private declaration, we could still check when we finish building a library that there was some definition for all public declarations. Another thing to think about would be moving code back and forth between the Anyways, definitely good to check that we actually got to a coherent consensus across all these cases, and especially good to check the case of redeclaring member functions as that seems important and not really considered. |
Related to moving code back and forth between the I think it's important that an out-of-line definition retains information from the declaration that's necessary to understand that definition. I don't think it's important that it retains information that's necessary to understand the interface, however: readers interested in the interface should be reading the Suggestion: omit from an out-of-line definition any modifiers that affect only the interface and not the definition ( I think it's OK to omit the If we go with this direction, we'll also need to decide whether these modifiers are disallowed in out-of-line definitions, or if they merely become optional. Perhaps disallowing them for now and reconsidering based on feedback would be a reasonable path forward. |
I believe they should be disallowed; where possible, there should only be one right way of doing things, and people may be misled that removing the extra keywords in a definition has an effect, forgetting to change the declaration. |
I should add, optional (neither required nor disallowed) redundant keywords in api:
impl:
A naive reader of the impl file may conclude that both |
Agree with all of @zygoloid 's comment except one tweak:
Here I would not. I think the default switching in an And similar to @jonmeow's example, I think it would result in confusion: api:
impl:
Forcing users to write And similarly, requiring The only downside I really see here is that naively moving a definition from an
Agree with @jonmeow that they shouldn't be optional. |
OK, I'm happy with that tweaked approach. So to summarize:
|
Replace library public-like `api` behavior with explicit `private` behavior, mirroring #665 Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
…ork (#561) This proposal defines the very basics of `class` types, primarily focused on: - use cases including: data classes, encapsulated types, inheritance with and without `virtual`, interfaces as base classes, and mixins for code reuse; - anonymous data types for called _structural data classes_ or _struct types_. Struct literals are used to initialize class values and ad-hoc parameter and return types with named components; and - future work, including the provisional syntax already in use for features that have not been decided. The intent is to both make some small incremental progress and get agreement on direction. As such it doesn't include things like nominal types, methods, access control, inheritance, etc. It proposes this struct type and literal syntax: ``` var p: {.x: Int, .y: Int} = {.x = 0, .y = 1}; ``` Note that it uses commas (`,`) between fields instead of semicolons (`;`), and no introducer for types or literal values. Incorporates decisions from #665 , #653 , #651 Co-authored-by: Geoff Romer <gromer@google.com> Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Replace library public-like `api` behavior with explicit `private` behavior, mirroring #665 Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
I think this is primarily addressed by #752 and other class-specific design work. Any concerns with considering this as proposed and no longer a proposal TODO? |
Agreed, this seems covered now. |
We should decide how we want to mark
public
members of record types (struct
s orclass
es depending on the resolution of #651) vs.private
members.Lots of folks seem very interested in avoiding the use of a "region" the way C++ works because this can make it hard when jumping to declarations (using whatever tool, but potentially an IDE) to understand the access control.
Note: I'm not suggesting that we have exactly
public
andprivate
(from C++) members. At least we need some analogy toprotected
from C++, and we may want something like "module internal" as well.One suggestion that seems quite popular:
public
the default, and have no annotation at all.private
annotation on any declaration that should be privateThe result as an example here:
The rationale for this particular set of rules is a bit surprising, so I'll try to walk through them informally here... Much of this is lifted from Discord Chat
#syntax
channel.The reason to annotate the
private
members locally is to reduce the degree of distant and potentially difficult to locate context. @josh11b is proposing a principle in #646 to help codify the reason reducing the contextual load in general, and this seems like a reasonably compelling case to apply this principle.The reason to make public members be the default is because their readability is a significantly higher priority -- the public API is what we would expect to be cited most and read most of everything. The implementation details (whether
private
as in C++ or a module-internal or evenprotected
) have a lower readability cost of any annotations. Similarly, data members are often the most common things to be private, and are likely to have a lower readability hit from the annotation than functions as they are a simpler construct in general (no parameters, etc).Making public the default isn't completely novel either: Kotlin does this as well
We could consider making an optional
public
specifier (which Kotlin does), but this seems prone to forming needless divergent styles and dialects of code. We couldn't teach people to expect apublic
specifier because not all code would use it. But especially coming from C++, that might be an easily made mistake.So the suggestion is to have saying nothing, which we understand always as a very significant impact, to be the way of saying "public".
And following from this, we suggest that a similar approach should be adopted for the exported declarations of a Carbon library. This would move away from marking those explicitly with
api
and have it be the default. Here, it is important to note that we can reliably check that any declaration in an implementation file either matches an exported declaration in an API file or is correctly marked asinternal
(or however it ends up being spelled). Again, the goal here isn't to suggest the exact semantic set of markers, but rather the strategy of the public API being the default, and the implementation details carrying tho annotations, as the readability cost of those annotations is lower due to them not being part of the public API.The text was updated successfully, but these errors were encountered: