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

allow to destructure record types with positional fields #3782

Open
ekuleshov opened this issue May 3, 2024 · 9 comments
Open

allow to destructure record types with positional fields #3782

ekuleshov opened this issue May 3, 2024 · 9 comments
Labels
feature Proposed language feature that solves one or more problems patterns Issues related to pattern matching.

Comments

@ekuleshov
Copy link

The Dart language allows to define a positional fields record and then destructure its fields like so:

  final (int, int, int) color = (1, 2, 3);  
  final (r, g, b) = color;
  print(r);

Also, in the following snippet the record type declaration containing field names is valid, but the field names declared in the record type can't be dereferenced:

  final (int r, int g, int b) color = (1, 2, 3);  
  print(r); // <-- "undefined name 'r'" at compile time

It would be great if the Dart language allowed to dereference these values by name. This would be a really handy feature when records with positional fields are passed around.

Consider the following example. The record type declaration in the map() method is valid, but these parameters can't be used in the lambda expression.

  List<String> list = ['a', 'b', 'c'];
  print(list.indexed.map(((int index, String s) en) => '$index:$s').join(', '));

Currently we have instead write lambda like (en) => '${en.$1}:${en.$2}', which is much less readable code.

@julemand101
Copy link

This are more fitting for the Dart Language issue tracker. Also, your last suggestion are very similar to: #3001

@ekuleshov
Copy link
Author

This are more fitting for the Dart Language issue tracker. Also, your last suggestion are very similar to: dart-lang/language#3001

Wasn't sure if that is a language feature or a compiler issue.
As you can see compiler allows to specify field names, but it does not allow to dereference them.

Please move/triage as you see fit.

@julemand101
Copy link

julemand101 commented May 3, 2024

  final (int r, int g, int b) color = (1, 2, 3);  

Since you have put the variable name color in here, it means you are creating a variable named color that contains a Record defined as the type (int r, int g, int b). The name of each variable in the record are not getting used so it kinda pointless besides for documentation.

Are you asking for this syntax instead should define the variable r, g, b and color? If so, it gets a bit confusing when having records with named arguments since should they also be defined as variables in your code or not?

final (int r, int g, int b) = (1, 2, 3);

Here, we don't have color so we can assume you want to destruct the record into three variables.

@ekuleshov
Copy link
Author

Here, we don't have color so we can assume you want to destruct the record into three variables.

I know. The catch is that compiler allows these param names when record name is declared after its type declaration. And that declaration looks similar to what you get when declaring record type in parameters of other methods.

In my other example, the type of en parameter ((int index, String s) en) => ... is accepted by the Dart compiler, but the compilation errors come from dereferencing index and s there.

@lrhn
Copy link
Member

lrhn commented May 3, 2024

The syntaxes for types and for patterns are eerily similar, for very good reasons, which is actually why what you're trying doesn't work
The parser needs to figure out whether it is a seeing a type or a pattern, and it uses the following identifier to decide that what came before is a type, not a pattern.

So you would have to write

final (int r, int g, int b) & color = ...;

to bind all the names ... if declaration patterns allowed & patterns. (They probably should, but today they don't.)

@eernstg
Copy link
Member

eernstg commented May 3, 2024

We can actually use a variant, as long as we stick to an <outerPattern> as the outermost construct:

void main() {
  final ((int r, int g, int b) && color) = (2, 3, 4);
  ...
}

@ekuleshov
Copy link
Author

The parser needs to figure out whether it is a seeing a type or a pattern, and it uses the following identifier to decide that what came before is a type, not a pattern.

I wonder if parser could delay its decision about exact type or infer a pattern for the time being until it is time to disambiguate exact type?

I used variable declaration for record, just to illustrate that compiler takes it as a valid syntax. Don't really have use for that variable (unless Dart would allow to do something like color.r instead of direct reference to r).

Other syntax variants discussed here and in dart-lang/language#3001 are adding some syntactic noise. Out of all, this one (:int r, :int g, :int b) would be concise in context of list.indexed.map(((:int index, :String s)) => '$index:$s').

@mmcdon20
Copy link

mmcdon20 commented May 3, 2024

See also #3487.

@lrhn
Copy link
Member

lrhn commented May 7, 2024

So this is a request for two things:

  • Allow final pattern id to match the same ways as final (pattern && id). I believe we considered that during the design, and it was mainly parsing ambiguities that made us not do that. You have to do something to make final (int x, int y) point = ... treat (int x, int y) as a pattern instead of a type. Something like final ((int x, int y) & point) = ... (thanks @eernstg). I don't expect that to change. Something like Replace record fields ($1, $2, etc.) with named fields if type contains field names (eg. (int a, int b)) #3487 does sound more likely (but still not something there are any current plans for).
  • Allow destructuring in parameter lists. That's a known request that we really want to deliver. The issue for that is Parameter destructuring #3001, so that only leaves the first item for this issue.

This is a language issue, so moving to language repository.

@lrhn lrhn transferred this issue from dart-lang/sdk May 7, 2024
@lrhn lrhn added feature Proposed language feature that solves one or more problems patterns Issues related to pattern matching. labels May 7, 2024
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 patterns Issues related to pattern matching.
Projects
None yet
Development

No branches or pull requests

5 participants