Skip to content

Implicitly required formal named parameters #4349

Open
@acarstoiu

Description

@acarstoiu

If I compile something like

void p({int a}) {
...
}

the compiler complains that The parameter 'a' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'., while it should simply understand that the named parameter a is required.

Proposal

A formal named parameter that has a non-nullable type and no default value, should be understood as being mandatory. I am surprised that no one has already asked for that (at least I did not find a relevant issue).

The required keyword can make a difference only in the case of a formal named parameter without a default value, but which has a nullable type. Specifically, it would force the caller to actually send null as a value instead of not specifying a value at all for the parameter. But that's hardly programmer-friendly so I deem the required keyword should be removed from the language.

Activity

added
featureProposed language feature that solves one or more problems
on May 2, 2025
lrhn

lrhn commented on May 2, 2025

@lrhn
Member

That would create a difference between function declarations and function types.

typedef IntEater = void Function({int value}); // Function type, parameter is *not* required.
void intEater({int value}) {} // Parameter is (with this proposal) required.
IntEater eater = intEater; // Compile-time error.
void maybeIntEater({int value = 0}) {} // Parameter is optional
IntEater eatOrZero = maybeIntEater; // OK.

It would also affect forwarding constructors.

class C {
  C.req({int a}); // required
  C.opt({int a = 42}); // optional
  factory C.fwdReq({int a}) = C.req;
  factory C.fwdOpt({int a}) = C.opt; // Forwarding constructor must not write default value.
}

It would require a way to specify that one of C.fwdReq and C.fwdOpt has a required parameter and the other an optional parameter. The required keyword does that today.

When you say "non-nullable type", that means that generic functions can have parameters that are optional depending on the type argument.

void consume<T>({T value}) {}
consume<int>(); // Error
consume<int?>(); // OK?

Or does it use the declared type, not the actual parameter type, which in this case is the type parameter T which is not nullable (nor is it non-nullable, it's potentially either).

I'm not unsympathetic to doing something here, but it's not as easy as this.
(Related issues include at least #1639 and #2232, where the latter tries to formalize precisely this "nullable means optional"/"null means no argument" approach.)

acarstoiu

acarstoiu commented on May 2, 2025

@acarstoiu
Author

typedef IntEater = void Function({int value}); // Function type, parameter is *not* required.

I'm missing something here, why doesn't the IntEater type also contain the compulsoriness of value?

class C {
C.req({int a}); // required
C.opt({int a = 42}); // optional
factory C.fwdReq({int a}) = C.req;
factory C.fwdOpt({int a}) = C.opt; // Forwarding constructor must not write default value.
}

As they are written, both forwarding constructors have a as required parameter. To preserve the behaviour of C.opt, one should define factory C.fwdOpt({int? a}) = C.opt.
That's because if a formal parameter's type is non-nullable, then its default value should be used when the function is called with null as the parameter's value.

When you say "non-nullable type", that means that generic functions can have parameters that are optional depending on the type argument.

Yes, precisely.

acarstoiu

acarstoiu commented on May 2, 2025

@acarstoiu
Author

Read a bit some messages on those threads. You're an advocate of the equivalency between "null actual value" and "no actual value" getting passed to a function.

But, since in Dart there's the notion of nullable type, I strongly believe "null actual value" and "no actual value" are to be treated alike only when the declared parameter type is non-nullable. That's just to allow the programmers do their own design, whether you consider it poor or not.

If the type is nullable, then the function body should expect to receive a null for the parameter's value, regardless of the presence of a default value in the declaration. In this case, the syntactic sugar proposed in this comment should be enough to promote the parameter's type to non-nullable inside the function's body.

mateusfccp

mateusfccp commented on May 2, 2025

@mateusfccp
Contributor

I am surprised that no one has already asked for that (at least I did not find a relevant issue).

There are at least two issues similar to this one. One of them was opened during the null-safety development, and was closed.

The other is still open and IIRC is slightly different but on the same line.

GitHub's search is just terrible.

Edit:

Found one of them, #878.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureProposed language feature that solves one or more problems

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @mateusfccp@lrhn@acarstoiu

        Issue actions

          Implicitly required formal named parameters · Issue #4349 · dart-lang/language