Skip to content
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

Closed
lrhn opened this issue May 15, 2024 · 3 comments · Fixed by #3880
Closed
Assignees
Labels
feature Proposed language feature that solves one or more problems wildcard-variables The wildcard-variables feature

Comments

@lrhn
Copy link
Member

lrhn commented May 15, 2024

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:

It is an error if an optional parameter (named or otherwise) with no default
value has a potentially non-nullable type except in the parameter list of an
abstract method declaration.

(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:

It is an error if an optional parameter (named or otherwise) with no default
value has a potentially non-nullable type except in the parameter list of an
abstract method declaration or a forwarding factory constructor, or if the
declared parameter name is _ and the parameter is not an initializing
formal or super parameter.

(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:

If an optional super-parameter corresponds to an optional parameter of the super-constructor, and no argument is given to
the super-paramater, then no argument is passed to the super-constructor either. It's a compile-time error if such an
optional super-parameter with an optional target has no default value, is potentially non-nullable, and the variable it
introduces in the parameter scope is referenced. Otherwise the variable will use the default value if no argument was
passed, even if no value is forwarded to the super constructor.

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.)

@lrhn lrhn added feature Proposed language feature that solves one or more problems wildcard-variables The wildcard-variables feature labels May 15, 2024
@scheglov
Copy link
Contributor

scheglov commented May 16, 2024

And come augmentations, it will only apply to the fully augmented declaration, not the individual steps.

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?

@lrhn
Copy link
Member Author

lrhn commented May 16, 2024

As currently specified, its definitely the case that:

It is an error if an optional parameter (named or otherwise) with no default value has a potentially non-nullable type except in the parameter list of an abstract method declaration.

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:

  1. It's an error if a non-augmenting (base) syntactic declaration has such a parameter.
  2. It's an error if a semantic declaration (the result of applying all augmenting declarations to the base declaration) has such a parameter.

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.
If that's the model, then it doesn't matter which of the perspectives above we use, because the parameters of the augmentation result have the same types, same optionality, and same default values as the base declaration after every augmentation step.

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 [Foo x], which would not even be valid without a default value, then I think it's perfectly reasonable to allow an augmenting declaration to add a default value, as [Foo x = const _NullFoo()]. No change, just filling in the blanks.
If we do that, then there should be no error unless the fully augmented declaration still has no default value. Any prior step in the augmentation chain, starting at the base declaration, doesn't have to be complete.

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.)

@kallentu
Copy link
Member

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.

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.

@kallentu kallentu changed the title Allow unnamed optional parameters to not have default value. [Wildcard Variables][spec] Allow unnamed optional parameters to not have default value. May 29, 2024
@kallentu kallentu self-assigned this Jun 4, 2024
copybara-service bot pushed a commit to dart-lang/sdk that referenced this issue Jun 7, 2024
…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 <[email protected]>
Reviewed-by: Lasse Nielsen <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems wildcard-variables The wildcard-variables feature
Projects
None yet
3 participants