Skip to content

Named arguments #4185

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

Open
cedvdb opened this issue Nov 29, 2024 · 5 comments
Open

Named arguments #4185

cedvdb opened this issue Nov 29, 2024 · 5 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@cedvdb
Copy link

cedvdb commented Nov 29, 2024

Named argument

As opposed to named parameters, named arguments is about using the parameter name on the call site.

Named arguments enable you to specify an argument for a positional parameter by matching the argument with its name rather than with its position in the parameter list.

Example:

void main() {
  final a = A(x: 1, y: 2);
  final another = A(y: 2, x:1);
}

class A {
  final int x;
  final int y;
  A(this.x, this.y);
}

Rationale:

The decision to use named or positional arguments can be a decision the call site should make.

Private properties

void main() {
  final a = A(x: 1, y: 2);
}

class A {
  final int _x;
  final int _y;
  A(this._x, this._y);
}

This could lead to other beneficial features down the line like:

Declaring all fields in a constructor

class A {
  final int x;
  final int y;
  final int z;
  A(this.*);
}

Related: Object spread shorthand

Syntax sugar ...Object is used in a constructor / function call to unpack labels:

void main() {
  final a = A(x: 1, y: 2);
  final b = B(...a, z: 3);
  // equivalent to
  final bWithoutSugar = B(x: a.x, y: a.y, z: 3);
}

class A {
  final int x;
  final int y;
  A(this.x, this.y);
}

class B {
  final int x;
  final int y;
  final int z;
  A(this.x, this.y, this.z);

...Object unpack the labels with the intersection between the parameters name and the object getters name.

Copies with null values

The last declaration of the field wins, allowing copying with null values (when the fields are not private).

void main() {
  final a = A(x: 1, y: 2);
  final another = A(...a, y: null);
}

class A {
  final int x;
  final int? y;
  A(this.x, this.y);
}
@cedvdb cedvdb added the feature Proposed language feature that solves one or more problems label Nov 29, 2024
@lrhn
Copy link
Member

lrhn commented Nov 29, 2024

I'm sure I have proposed something like this before, possibly as part of some other feature (I can't find an issue right now).

It's a nice idea which allows users to refer to parameters by name, when they have a name, even if they are not named parameters.

The risks are that the names are not really part of the function value, they're just metadata on the static function types.

  • You can't use those names in a dynamic invocation.
  • Any operation on types may affect the metadata. We'll have to specify precisely how it's propagated through all type operations (with Up and Down being the biggest risks, and Norm probably not mattering since it's only used at runtime).
  • It becomes a breaking change to change the name of a positional parameter. Even if you never intended it to be used as a parameter name in that way, there is no way to opt out. (Well, you can make it a private name, but that's ugly, and we don't want everybody making their positional parameters private just to not get trapped with a name that they want to change, effectively getting trapped with an ugly private name instead.)

@cedvdb
Copy link
Author

cedvdb commented Feb 19, 2025

(Well, you can make it a private name, but that's ugly, and we don't want everybody making their positional parameters private just to not get trapped with a name that they want to change, effectively getting trapped with an ugly private name instead.)

In what I envisioned here

  • named parameters are removed, I don't see the point, it's also a breaking change to rename those.
  • all params can be used as named arguments, you can't opt out.

Is it that bad to have parameters name part of the public contract when compared with the potential benefits ?

You can't use those names in a dynamic invocation.

The dynamic issue seems like a non issue to me. Dynamic usages are pretty seldom and if you really need to label, you can cast.

@gryznar
Copy link

gryznar commented May 8, 2025

  • It becomes a breaking change to change the name of a positional parameter. Even if you never intended it to be used as a parameter name in that way, there is no way to opt out.

Python here has positional only args:

def foo(bar: str, /): ...

If we decide to have nullable args / args with default as optional, we can reuse [...] here

@munificent
Copy link
Member

I'm sure I have proposed something like this before, possibly as part of some other feature (I can't find an issue right now).

This is basically what my "Enhanced Normal Parameters" strawman is. I haven't written it up in public form yet, but maybe I should.

It's how most other languages with named arguments work. There are some real trade-offs with it but I suspect that overall it's a better approach. Certainly it would make parameter list syntax cleaner and simpler.

@gryznar
Copy link

gryznar commented May 10, 2025

@munificent is it going to happen in the future altogether with: #2232? Lack of named arguments by default and treating optional only by passing [] and {} in signatures is why Dart is for me unnecessary verbose..

Python approach here to treat specially only positional-only and keyword-only args is IMO much better approach.

With these 2 approaches, [] and {} could be reused only for positional-only / keywords-only

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
Projects
None yet
Development

No branches or pull requests

4 participants