Description
This is a tracking bug for implementing support for generic function type syntax (generic typedef) in Dart 1.5.
Proposal: https://gist.github.com/eernstg/ffc7bd281974e9018f10f0cb6cfee4aa
The corresponding individual issues will be listed here:
- Language team decision on syntax (private issue): dart-lang/dart-lang-evolution#88
- Analyzer implementation issue: Implement generic function type syntax in the analyzer #27969
- VM implementation issue: Implement generic function type syntax in the VM. #27966
- Dart2js implementation issue: Implement generic function type syntax in dart2js #27967
- DDC implementation issue: Implement generic function type syntax in DDC #27971
- dartfmt issue: Implement support for generic function types dart_style#563
- dartdoc issue: Implement generic function type syntax in dartdoc dartdoc#1321
- Make sure changelog has an entry for this
- Final specification issue: Write specification for generic function type syntax #27970
Description
Dart 2 supports generic methods and generic tear-offs (or anonymous functions). This means that a function can request a function that is generic:
// Takes a function `f` that is generic on T.
void foo(A<T> constructorForA<T>()) {
A<int> x = constructorForA<int>();
A<String> x = constructorForA<String>();
}
It is straightforward to add the syntax to the existing syntax for function types for parameters (as was done in the example). However, we don't have an easy way to do the same for fields or local variables:
// Does *not* do what we want it to do:
typedef A<T> ConstructorForAFun<T>();
A f; // A function that returns an `A<dynamic>`.
We already used the most consistent place for the generic method argument as a template argument to the typedef
itself. If we could go back in time, we could change it as follows:
typedef<T> List<T> TemplateTypedef();
TemplateTypedef<int> f; // A function that returns a List<int>.
TemplateTypedef f; // A function that returns a List<dynamic>.
typedef List<T> GenericTypedef<T>();
GenericTypedef f; // A function that is generic.
List<int> f<int>();
List<String> f<String>();
Given that this would be a breaking change we have considered alternatives and are now exploring new typedef syntax altogether. The idea is to provide syntax that can also be used for locals and fields at the same time.
For example:
typedef F = (int) -> void; // Function from (int) to void.
typedef F<T> = () -> List<T>; // Template Typedef.
typedef F = <T>(T) -> List<T>; // Generic function from T to List<T>.
This way we would solve 3 issues at the same time:
- users often forget the parameter name and expect
typedef void F(int)
to be a function that takes an int. - users can write the function type of fields and locals without needing to write a typedef.
- of course: we can write the type of a generic function.
While investigating different syntax we found that the following points need consideration:
- nullability: the syntax must be nullable without too much hassle:
(int)->int?; // A function that is nullable, or that returns a nullable integer? Problem disappears with <- int <- (int)? ; vs int? <- (int)
- readability
- interactions with union types (if we ever want them).