-
Notifications
You must be signed in to change notification settings - Fork 205
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
[Wildcard Variables][spec] Allow unnamed optional parameters to not have default value. #3807
Comments
When you say "fully augmented declaration", how does this reconcile with "The function augmentation specifies any default values. Default values are defined solely by the original function." from the augmentation specification? As it is specified now, it seems that you provide default values only on the original declaration, not in any other steps. Do we plan to change this? |
As currently specified, its definitely the case that:
does not apply to augmenting method declarations, since they cannot declare default values, and they must declare parameters with the same optionality and type as the augmented declaration. Then there are two ways to look at where the rule does apply:
With the current specification, I'd say that the declaration you get from applying an augmenting method declaration to another method declaration, the augmented declaration (which is a base declaration or the result of applying some prior augmenting declarations to a base declaration), inherits the default values of the parameters of the augmented declaration. I prefer the second view. I do so because I don't think it's a given that we will keep the "augmentations cannot add default values" rule. And because I think it's important that we use that perspective in cases where there is a difference, and that is the more useful perspective. If we change the rule for default values, we can still say that an augmentation cannot change a default value, but if a base declaration has a parameter In general, I think most of the "completeness rules" we have for declarations (method of non-abstract class must have a body, non-nullable optional parameter must have default value, non-redirecting generative constructor must initialize all final fields, probably more), should only apply to the "fully augmented" declaration. That's where we require completeness. Some of our rules for syntax are to avoid conflicts locally, or overspecifying (for example: a function declaration must not have two parameters with the same name, or a non-optional parameter must not have a default value), other rules are completeness rules like the ones above. With augmentations, we should apply the conflict-like rules to every syntactic declaration, and the completeness rules only to the complete, fully augmented, semantic declaration. The big task is to figure out which rules are which! (There may be some arguments there - for example I'd consider the (now rejected) "don't implement the same type twice" a local conflict-like rule, and wouldn't mind different augmentations adding the same interface, but I'm not sure everybody would agree.) |
I'm fine with this change. Seems to make sense and if it doesn't once we come to implement it, we'll revisit. cc. @dart-lang/language-team if anyone else has any other opinions. |
…o default value. Bug: dart-lang/language#3807 Change-Id: Ibeb29d3702b74379b64e8965c3ef9709c7bf2f41 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/369780 Commit-Queue: Kallen Tu <kallentu@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com>
Should this be a valid method definition? void foo([Uint8List _]) {} You can't change If the above is valid, how about this? void bar([Never_]) {} Notes on implementation for dart2js dart2js implements argument defaulting for instance methods (and static methods that have tear-offs) by having multiple entry points (stubs) that add the missing arguments and then call the primary entry point (which expects all the arguments). The primary entry point does type checks (potentially checking the defaulted value). This avoids sentinels and a whole raft of js-interop problems with the JavaScript sentinel value It is not clear how to modify the default-then-check pattern for wildcards. I suppose we could add a sentinel value that is outside the Dart type system, and modify the entry checks (i.e. It is this second part, making sure we can represent the possibility of a sentinel in the dart2js internal type system, that makes implementing "unnamed optional parameters without a default value" a large work-item for dart2js. We can do the work, but is the feature worth the effort? I suggest initially that unnamed optional parameters with a non-nullable type require a default value. |
I think there's pretty broad interest in allowing all parameters to have non-constant defaults. In any case, yes I think our general perspective is that this should be allowed. If I'm overriding a method, and it has three optional parameters, and I don't care about the first two, why force me to list out a default for them if I'm never going to use them?
Given the constraints you describe above, what about making the primary entry point expect not all of the arguments, but rather all of the non-wildcard arguments. You would then (in spec compliant mode) need to move any type checks for the wildcard arguments only into the stubs. This has a code size cost, but only in spec compliant mode, and only when the feature is used, making it pay as you go. Would this help?
I am open to reconsidering this if really necessary, but I'm also somewhat resistant to designing the language around the particulars of this calling convention. Each individual decision may seem small, but cumulatively they weigh on us as language tech debt. |
If the changes to support What worries me about non-constant defaults is that tends to force an implementation strategy of defaulting inside the method. It becomes harder to make a call fast because of what you know at the call-site, since the defaulting is constrained to happen in the scope of the parameters or instance.
Not really, but I didn't mention all the constrains. Currently the main entry point, since it does checks, is also the dynamic call entry point and the In
I agree that "unnamed optional parameters do not need a default value" is a nice feature. But we could add it later. If we add it later, none of the back-ends need to handle it now (wasm is also broken) and wildcard parameters behave just like ordinary parameters plus the static constraint that they cannot be used. That is what users need to write today. How many potentially-unnamed parameters are actually optional? I see lots of compelling examples for required arguments but not so many for optionals. |
I agree that the combination of being positional, optional and non-nullable is rare, and wanting to ignore the value of an optional parameter that is not nullable is exceedingly rare. (It's there for a reason, and it's not nothing (not It may be mostly in tests that it turns up. Maybe only in tests of wildcards (there's a reason I stumbled on it). I'd like the feature, because it feels right. (But then, we've postponed #1076 for 11 years, and it should really have been there since day 1. It's always been implementation constraints that have gotten in the way, not that it's not an awesome idea. This one is far from as impactful.) |
During our weekly meeting, the language team has decided to remove this from the spec. We can perhaps do it in a future release, but knowing our track record, we probably won't get to it. |
I think my proposal handles dynamic calls fine (you have all of the same selectors as before with all of the same semantics as before), but I don't entirely follow the constraints around Function.apply. In any case, we discussed this in the language team meeting this morning and agreed to remove it from the spec for this feature. Decision: we will not allow unnamed optional parameters to not have a default value in this feature release. We will file an issue to consider it as a future feature, possibly as part of non-const default values |
…al parameters for wildcards. Reverting https://dart-review.googlesource.com/c/sdk/+/371560. Bug: dart-lang/language#3807 Change-Id: I3933d7d6117b90cc0a091c8e3ce1e5bcf8061ec0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/377722 Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Chloe Stefantsova <cstefantsova@google.com> Commit-Queue: Kallen Tu <kallentu@google.com>
With "wildcard-variables", a parameter can have no name.
For example
void foo(int _) { ... }
does not introduce a name in the parameter scope, the parameter value is inaccessible.Or stated differently: The parameter does not introduce a variable.
The purpose of optional parameter default values is to ensure that a parameter variable has a value when it's read, even if no argument value was passed. A parameter which cannot be read or used in any, one where there is no variable at all, way does not need a default value to initialize a variable.
Proposal: It is not a compile-time error for a optional non-initializing non-super parameter to not have a default value, even if its type is not nullable.
The existing clause is:
(Or of a forwarding factory constructor, they also cannot declare default values. And come augmentations, it will only apply to the fully augmented declaration, not the individual steps.)
For wildcard variables only, this should be changed to:
(If we have a better way of phrasing that a declaration is non-binding, we can use that instead of "the declared ... name is
_
".)We have to exclude initializing formals,
this._
, and super parameters,super._
ifwhen we allow those, because the value of that argument is used for something, even if it cannot be referenced.(If we make it possible to forward not having an argument, then
super._
can safely be forwarded to another optional positional parameter without having a default value, it will just forward the absence of an argument and let the super-constructor use its default value. Maybe we should just do that anyway! Sub-proposal:And a
_
-named parameter is never referenced, so that just works. As long as we can only omit trailing positional parameters, and we cannot combine explicit positional arguments to the super-constructor with positional super-parameters, the forwarding will also work correctly.Or something.)
The text was updated successfully, but these errors were encountered: