language
language copied to clipboard
allow to destructure record types with positional fields
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.
This are more fitting for the Dart Language issue tracker. Also, your last suggestion are very similar to: https://github.com/dart-lang/language/issues/3001
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.
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.
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.
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.)
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);
...
}
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')
.
See also https://github.com/dart-lang/language/issues/3487.
So this is a request for two things:
- Allow
final pattern id
to match the same ways asfinal (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 makefinal (int x, int y) point = ...
treat(int x, int y)
as a pattern instead of a type. Something likefinal ((int x, int y) & point) = ...
(thanks @eernstg). I don't expect that to change. Something like https://github.com/dart-lang/language/issues/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 https://github.com/dart-lang/language/issues/3001, so that only leaves the first item for this issue.
This is a language issue, so moving to language repository.