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

Whether the variable name in the tuple should be forbidden? #3044

Closed
Silentdoer opened this issue May 5, 2023 · 6 comments
Closed

Whether the variable name in the tuple should be forbidden? #3044

Silentdoer opened this issue May 5, 2023 · 6 comments
Labels
request Requests to resolve a particular developer problem

Comments

@Silentdoer
Copy link

Whether the variable name in the tuple should be forbidden because it cannot be used, e.g. (double x, int a) should only be written as (double, int)?

(double, int $2) Is this writing also prohibited?

@Silentdoer Silentdoer added the request Requests to resolve a particular developer problem label May 5, 2023
@lrhn
Copy link
Member

lrhn commented May 5, 2023

Why should we disallow names for positional fields in record types?

Is it confusing that it's allowed? Is it too easy to forget the {...} around the named fields?

We deliberately allow names for positional record fields in record types, the same way we allow names for positional parameters in function types, even if they have no functional effect. They can be used for documentation.

So, it's fine to write:

Iterable<(K key, V value)> mapEntries<K, V>(Map<K, V> map) => map.entries.map((e) => (e.key, e.value));

The names are useful here.

We currently disallow names that would conflict with another field's name.
We don't allow (int foo, {int foo}) or (int, {int $1}) because those names would conflict with other names,
or even (int, int $1).
We do allow (int $1, int $2) because those name won't conflict with the name of another field.

So, all in all, the current behavior is consistent and by design.

If you don't want to write names for positional record fields, you can obviously choose to not do so.

@munificent
Copy link
Member

Agreed with @lrhn. While names on positional fields in record types are somewhat confusing, it's also useful for documentation and consistent with positional parameters in function types. This was a deliberate design choice.

@munificent munificent closed this as not planned Won't fix, can't repro, duplicate, stale May 5, 2023
@Silentdoer
Copy link
Author

Silentdoer commented May 5, 2023 via email

@Reprevise
Copy link

We can use the name of the function parameter, but the position parameter name of the tuple can only be replaced with a symbol such as $1. The return value type is (int a, int b), res.a is not allowed, it can only be res.$1

I'm sure there's a reason for not allowing it, but I would like to be able to access my positional parameters by name. My project has some "refactors" of removing classes like _ChartData and replacing them with record typedefs, and we need to make the choice between making the record named, and updating the "constructors", or making them positional like the class, but updating the accessors to $1 or $2 when we should just be able to access it by name regardless. I'm sure there's an elaborate discussion in a separate issue on this subject but I can't find it right now.

typedef _ChartData = (DateTime date, double value);

final _ChartData data = (/* */);
print(data.date) // should work imo

final class _ChartData {
  const _ChartData(this.date, this.value);

  final DateTime date;
  final double value;
}

final _ChartData data = _ChartData(/* */);
print(data.date); // works fine

@munificent
Copy link
Member

I'm sure there's a reason for not allowing it, but I would like to be able to access my positional parameters by name.

Issue #3487 goes into this in some detail.

My project has some "refactors" of removing classes like _ChartData and replacing them with record typedefs

If it were me, I would consider keeping those classes. If you have a type that has a meaningful name, meaningful state, accessors for that state, and you want to write a constructor for it... that's a class.

@Reprevise
Copy link

If it were me, I would consider keeping those classes. If you have a type that has a meaningful name, meaningful state, accessors for that state, and you want to write a constructor for it... that's a class.

The contents of the class _ChartData are listed in full above, it wasn't shortened for readibility. Considering that, I went with using named records and nothing else had to be changed, and now we have the benefit of implicit equality. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

4 participants