-
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
Alternative naming for has_extern
keyword
#3986
Comments
|
|
To be clear -- I think the leads need to decide both on a name, but also on whether they want a keyword marking this at all. While there has been some discussion of this marker being desirable in some ways, I think it's worth getting the leads do clearly decide that the benefits outweigh the costs. (FWIW, as a lead, I'm currently ambivalent on whether its worth having this marker. There are very clear benefits, but there are also drawbacks and I'm having a hard time getting to a high-confidence stance here.) |
@chandlerc Do the arguments in #3980 accurately capture your perspective on the trade-offs of whether the keyword should be provided? If not, perhaps you could detail the trade-offs that you're seeing? i.e.:
|
I think we have a few options in front of us:
We've recently said we want to avoid repeating annotations between declaration and definition, which suggests we don't want the fourth option. For the third option, we could use We have previously talked about a model where, for types with |
I think if you have the code:
Then this is going to be a linker error. I'd been expecting that, when If |
When compiling |
The example was intended for a "has_extern does not exist" case; the difference is that if "b" were instead doing |
I see. Yes, there's a benefit here that a declaration annotated with There's perhaps an overarching principle that we might want to consider adopting here: we could try to guarantee that if your library still compiles when you remove a non-exported import, then it is safe to remove that import. This guarantee would be very useful for tooling seeking to automatically minimize the imports of a file. The |
@zygoloid and I discussed this and I think we have a thought of what might be a reasonable direction here, unless someone finds a problem with it. The key is that we'd prefer to have the syntax reflect some fundamental property of the type rather than the existence of some other thing (that there exists an extern declaration). We think we can get there though, the meaning we're trying to confer is:
Combined, they enable more sparse and minimal dependencies when desirable. We don't have a great name for this property, but we have been using To finish satisfying the idea of having the syntax reflect a fundamental property, we'd like to suggest requiring that all the declarations, including the definition, have the This does suggest a small extension to #3986 which is to allow in a single API file: extern class C;
extern class C {
// ...
} Or to allow an API file: package Widget;
extern class C; With an implementation file: impl package Widget;
extern class C {
// ...
} These would not take advantage of the allowed separate library for their extern declaration, but would be effectively reserving the option of adding such a separate library in the future. We would still avoid the need to do any merging here, as for an extern declaration in one library to be the same entity as an extern definition in another library, the defining library must import the declaring library. And we would still get most of the validation in the face of refactorings and other changes as they would when removing an import result in no preceding extern forward declaraiton, and there must be at least one. The main downside that I see here (beyond that this keyword isn't ideal or obviously tied to the semantic as mentioned above), is that there may be some confusion when writing a definition of a class with What do others think about this? |
In the case where you have an extern declaration in the API file of library "a", a forward declaration in the API file of library "b", and a definition in the impl file of library "b", are you saying that both API files would have the same Is the statement that what you can do with the name is the same, so users should not care about the difference, since the only factors that matter are whether you can see a declaration and whether you can see a definition? |
Given that we require the API file of "b" to import "a", could we disallow adding the second forward declaration there?
More, whether you directly import a definition. |
To be sure I understand correctly, in the proposal, this is essentially the "Allow up to two declarations total" option. Previously that had been declined because it prevents adding non- |
I also thought we expected documentation of entities in the owning library's API file even if there was an extern declaration in another library? |
This whole situation of an extern declaration in one library and a definition in an implementation file of a different library seems strange to me, and it's not clear to me how this comes about or what semantics we'd want it to have. I think a more concrete example would help clarify my thinking. Can we come up with one? |
The most interesting example to me is when interface implementation is involved. So something like:
The idea here is that you generally only need to know that a type implements an interface, not see the definition of the implementation, to be able to pass values and objects of that type to functions requiring that interface. |
Should the class definition be in "o" here? Or is the point to demonstrate an issue with "extern impl" rather than "extern class"? |
Point was to show the issue with extern impl. |
Following a bunch of discussion, here's one possibility:
An When an
The hope is that this will give us better diagnostics, better human readability and understandability of the code, a single meaning for How well does this work for people? |
There was discussion about this in the open discussion yesterday. There aren't many notes, and since discussion is relevant here anyways, I'm going to try to summarize what I recall here. I think there's consensus now regarding the interface issue noted by josh11b above due to concerns about how the impl's library ownership is expressed, particularly if a developer tried to move the declaration of My understanding from the meeting is that there's still a desire to express that a declaration must be directly imported for types where all declarations are in the same library (i.e., not A few options we went over in the meeting were:
If I'm missing anything in this summary, let me know. |
Regarding
That could be partly addressed by scoping ( |
FWIW, the That said, I definitely see the point about a risk of verbosity. I think some of this depends on whether these end up useful in very narrow, targeted cases, or if we end up needing lots of types to use the pattern. If the latter, the verbosity seems like it will quickly be a problem. If it does, I think Jon's suggestion here is great:
While there has been reticence, I think for a case like this, and notably "forward declarations only", it would be a reasonable way to address verbosity. It's not clear we need it right away or whether to keep it in our back pocket until we can see a bit more how widely we want to use this feature in practice. Overall, I feel like even if we end up tweaking (as above, or in some other way) the syntax to address verbosity, this direction provides a nice starting point with strong semantic properties to let us move forward. |
After checking with leads, let's call this decided with the |
@chandlerc For the proposal, can you please provide the rationale for why leads are choosing |
From @zygoloid's comment above:
For the verbosity issue: If this is used with repeated types that make the verbosity a problem, we should explore some factoring or grouping structure that factors out the verbose library component, such as |
Okay, I'll try to figure out how to map this to project goals. |
Sorry, one point of clarification... Is this allowed:
I want to be sure, as a consequence is that arbitrary libraries may later add an
This is why I'm inferring this, but I want to be sure that the desire to restrict use is a feature. Similarly, it sounds like multiple |
Clarifications are good!
I think there is a missing "not" before "restrict" here. But yes, I think "We do not require there to be an extern declaration" is actually saying "We do not require there to be an extern [library] declaration". And this would allow an API file to require direct-import-to-use without factoring out a forward declaration to a separate library. The idea behind this is that enabling that requirement is a breaking change for consumers of the library and so might be made independently or in advance of actually creating a separate-library declaration.
They all need to be imported into the specified library, but otherwise, unless we encounter a reason to restrict them when implementing them, I would allow them. If we do end up finding reasons to restrict them, I think that would likely be fine, but I would wait until they show up. And tagging @zygoloid to make sure I'm not misrepresenting / remembering anything ehre. |
I think the desire to have a single canonical declaration for everything and to not need to do any merging at import time are good and known reasons for a restriction here. We'd need to do some non-trivial import-time merging work to get the right behavior with multiple imported (Otherwise I agree.) |
Summary of issue:
#3980 is looking for a keyword to mark that an entity has an
extern
declaration. Tentatively it useshas_extern
; is there a different name that leads would prefer?Details:
So far, options I think have been brought up look similar:
has_extern
is_extern
externed
I'm currently going with
has_extern
because it's unambiguous, although the_
seems atypical for keywords.is_extern
seems to have the wrong implication.externed
seems more on the side of confusion.Not marking is an option, although as noted in #3980 it brings benefits for validation. There may also be some other form of marking that would work rather than a simple modifier keyword.
Any other information that you want to share?
No response
The text was updated successfully, but these errors were encountered: