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 type instantiation as expression. #123

Closed
lrhn opened this issue Dec 4, 2018 · 9 comments
Closed

Allow type instantiation as expression. #123

lrhn opened this issue Dec 4, 2018 · 9 comments
Labels
constructor-tearoffs feature Proposed language feature that solves one or more problems

Comments

@lrhn
Copy link
Member

lrhn commented Dec 4, 2018

Dart does not allow you to write List<int> as an expression evaluating to a Type object, instantiating the generic class. This is inconvenient to users, who have to resort to helper functions like Type typeOf<T>() => T;.

Dart does not allow you to write genericFunction<int> to create a specific type instantiation of a generic function, but it does allow T id<T>(T x) =>x; int Function(int) intId = id; to implicitly instantiate the generic function. It should be possible to write the type explicitly.

Dart does not allow constructor tear-offs - the syntax Foo<int> or Foo<int>.named are not valid expressions. if Foo<int> was allowed syntax, then this would be an easy extension.

So, as a feature, Dart should allow type instantiation of all generic elements (typedefs, classes and functions) and allow constructor tear-offs.
The syntax List<int> can be seen both as a type and as the name of the unnamed constructor. I propose using the context type to distinguish: If the context type is Function or any function type, the expression is considered a tear-off of the unnamed constructor, otherwise it is a Type object.

This looks like two features, but because of the syntactic overlap, they should be implemented at the same time.

And if expression < type* > is valid expression syntax, we can also do explicit instantiation of generic method tear-offs.

(If we extend type literal syntax to allow List<int>, then we might also want to allow int? as a NNBD type literal).

@lrhn lrhn added the feature Proposed language feature that solves one or more problems label Dec 4, 2018
@eernstg
Copy link
Member

eernstg commented Dec 4, 2018

We have discussed this feature earlier, along with some grammar ambiguities. I believe that we could avoid those syntactic difficulties by putting this construct near expression in the set of grammar rules. This means that there are a number of locations where it cannot occur (because they require an assignableExpression or a postfixExpression or some other more specific thing), but in all those cases we would be able to use parentheses to make it a primary, which is allowed "everywhere". For instance, we wouldn't be able to do List<int>.toString(), but we could do (List<int>).toString(). This should be helpful in order to disambiguate named contructor invocations from other expressions (because we should still be able to create a list using List<int>.filled(10,0)).

@leafpetersen
Copy link
Member

We could also consider generic getters as part of this. Unfortunately, I haven't found any good syntax for generic setters. x =<T> e could work, but sure is ugly.

@munificent
Copy link
Member

If the context type is Function or any function type, the expression is considered a tear-off of the unnamed constructor, otherwise it is a Type object.

I think constructor tear-offs are more useful than Type objects, so I wish we could make those the default. Otherwise, things like this don't work (do they?):

(removeDuplicates ? List.from : Set.from)(elements)

Otherwise, this SGTM.

We could also consider generic getters as part of this.

You know, I feel like I should want this in principle because it generalizes, but I can't say I've ever actually found myself wanting it in practice.

Unfortunately, I haven't found any good syntax for generic setters. x = e could work, but sure is ugly.

Eek, yeah. Does this not work:

object.setter<T> = value;
setter<T> = value;

?

@natebosch
Copy link
Member

I think constructor tear-offs are more useful than Type objects, so I wish we could make those the default.

It would be breaking to make var l = List tear off the constructor instead of being a type.

Since var l = List.from; or var l = List<int>.from; already are errors I think it would not be breaking if we use new as the "magic" name for the unnamed constructor: var l = List.new.

@leafpetersen
Copy link
Member

This should cover nullable types as well: e.g int? as a literal.

@lrhn
Copy link
Member Author

lrhn commented Nov 9, 2020

Allowing int? as an expression might get us into parsing ambiguities, fx. int?[42] can be both (int?)[42] and (int)?[42].
It's most likely never going to be an issue for bug-free code, but we'll have to disambiguate in some way and it might make some error recovery harder.

@eernstg
Copy link
Member

eernstg commented Mar 8, 2021

Note that a very old SDK issue, dart-lang/sdk#11923, was used to discuss this topic as well. I closed dart-lang/sdk#11923 as a duplicate of this one, because this one is directly phrased as a language feature proposal and has the more recent discussion.

@eernstg
Copy link
Member

eernstg commented Jul 8, 2021

Added label 'constructor-tearoffs' — it's a completely different topic, but there is an organizational relation: This feature is actually being implemented now as part of the experiment constructor-tearoffs.

@eernstg
Copy link
Member

eernstg commented Dec 7, 2021

Closing: This feature is included today.

@eernstg eernstg closed this as completed Dec 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
constructor-tearoffs feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

5 participants