Chromium Code Reviews| Index: GENERIC_METHODS.md |
| diff --git a/GENERIC_METHODS.md b/GENERIC_METHODS.md |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..72b0e7f868b43fc779acc13d4e78fe894c00bf8b |
| --- /dev/null |
| +++ b/GENERIC_METHODS.md |
| @@ -0,0 +1,190 @@ |
| +# Strong mode generic method prototype syntax |
| + |
| +This is a summary of the current (as of January 2016) supported comment-based |
|
Bob Nystrom
2016/01/13 22:43:20
Nit: Remove "supported" since it's used later in t
Leaf
2016/01/14 00:28:54
Done.
|
| +generic method syntax supported by the analyzer strong mode and the Dart Dev |
| +Compiler. The comment-based syntax essentially uses the proposed actual generic |
| +method syntax, but wraps it in comments. This allows developers to experiment |
| +with generic methods while still ensuring that their code runs on all platforms |
| +while generic methods are still being evaluated for inclusion into the language. |
| + |
| +## Declaring generic method parameters |
| + |
| +Generic method parameters are listed after the method or function name, inside |
| +of angle brackets and comments. |
|
Bob Nystrom
2016/01/13 22:43:20
How about:
"Generic method parameters are listed
Leaf
2016/01/14 00:28:54
Done.
|
| + |
| +```dart |
| +// This declares a function which takes two unused generic method parameters |
| +int f/*<S, T>*/(int x) => 3; |
| +``` |
| + |
| +As with classes, you can put bounds on type parameters. |
| + |
| +```dart |
| +// This declares a function which takes two unused generic method parameters |
| +// The first parameter (S) must extend num |
| +// The second parameter (T) must extend List<S> |
| +int f/*<S extends num, T extends List<S>>*/(int x) => 3; |
| +``` |
| + |
| +Class methods (instance and static) can be declared to take generic parameters |
| +in the same way. |
| + |
| +```dart |
| +class C { |
| + static int f/*<S, T>*/(int x) => 3; |
| + int m/*<S, T>*/(int x) => 3; |
| +} |
| +``` |
| + |
| +Function typed parameters, local functions, and function expressions can also be |
| +declared to take generic parameters. |
| + |
| +```dart |
| +// foo takes a generic method as a parameter |
| +void foo(int f/*<S>*/(int x)) {} |
| + |
| +// foo declares a local generic function |
| +void foo() { |
| + int f/*<S>*/(int x) => 3; |
| + return; |
| +} |
| + |
| +// foo binds a generic function expression to a local variable. |
| +void foo() { |
| + var x = /*<S>*/(int x) => x; |
| +} |
| +``` |
| + |
| +We do not currently support a way to declare a function as returning a generic |
| +function. This will eventually be supported using something analogous to Dart |
| +typedefs. |
| + |
| +## Using generic method parameters |
| + |
| +The previous examples declared generic method parameters, but did not use them. |
| +You can use a generic method parameter `T` anywhere that a type is expected in |
| +Dart by writing a type followed by `/*=T*/`. So for example, `dynamic /*=T*/` |
| +will be interpreted as `dynamic` by all non-strong mode tools, but will be |
| +interpreted as `T` by strong mode. In places where it is valid to leave off a |
| +type, simply writing `/*=T*/` will be interpreted as `dynamic` by non-strong |
| +mode tools, but will be interpreted as `T` by strong mode. For example: |
| + |
| +```dart |
| +// foo is a generic method which takes a single generic method parameter S. |
| +// In strong mode, the parameter x will have type S, and the return type will |
| +// be S |
| +// In normal mode, the parameter x will have type dynamic, and the return |
| +// type will be S. |
| +dynamic/*=S*/ foo/*<S>*/(dynamic/*=S*/ x) { return x; } |
| +``` |
| + |
| +This can be written more concisely by leaving off the `dynamic`. |
| + |
| +```dart |
| +/*=S*/ foo/*<S>*/(/*=S*/ x) {return x;} |
| +``` |
| + |
| +Note that the generic parameter is in scope in the return type of the function, |
| +in the argument list of the function, and in the body of the function. When |
| +declaring local variables and parameters, you can also use the `/*=T*/` syntax with `var`. |
| + |
| +```dart |
| +// foo is a generic method that takes a single generic parameter S, and a value |
| +// x of type S |
| +void foo/*<S>*/(var /*=S*/ x) { |
| + // In strong mode, y will also have type S |
| + var /*=S*/ y = x; |
| + |
| + // In strong mode, z will also have type S |
| + dynamic /*=S*/ z = y; |
| +} |
| +``` |
| + |
| +Anywhere that a type literal is expected, you can also use the `/*=T*/` syntax to |
| +produce a type literal from the generic method parameter. |
| + |
| +```dart |
| +void foo/*<S>*/(/*=S*/ x) { |
| + // In strong mode, s will get the type literal for S |
| + Type s = dynamic /*=S*/; |
|
Bob Nystrom
2016/01/13 22:43:20
Generic method type parameters are reified?
Jennifer Messerly
2016/01/13 22:49:33
In DDC, they will be, yes.
Leaf
2016/01/14 00:28:54
Just to be clear - the intention is that they will
|
| + |
| + // In strong mode, this attempts to cast 3 as type S |
| + var y = (3 as dynamic /*=S*/); |
| +} |
| +``` |
| + |
| +## Instantiating generic classes with generic method parameters |
| + |
| +You can use generic method parameters to instantiate generic classes using the |
| +same `/*=T*/` syntax. |
| + |
| +```dart |
| +// foo is a generic method which returns a List<S> in strong mode, |
| +// but which returns List<dynamic> in normal mode. |
| +List<dynamic /*=S*/> foo/*<S>*/(/*=S*/ x) { |
| + // l0 is a list literal whose reified type will be List<S> in strong mode, |
| + // and List<dynamic> in normal mode. |
| + var l0 = <dynamic /*=S*/>[x]; |
| + |
| + // as above, but with a regular constructor. |
| + var l1 = new List<dynamic /*=S*/>(); |
| + return l1; |
| +} |
| +``` |
| + |
| +In most cases, the entire type argument list to the generic class can be |
| +enclosed in parentheses, eliminating the need for explicitly writing `dynamic`. |
| + |
| +```dart |
| +// This is another way of writing the same code as above |
| +List/*<S>*/ foo/*<S>*/(/*=S*/ x) { |
| + // The shorthand syntax is not yet supported for list and map literals |
|
Bob Nystrom
2016/01/13 22:43:20
Will this be fixed soon? If so, I wouldn't mention
Jennifer Messerly
2016/01/13 22:49:33
https://github.com/dart-lang/sdk/issues/25407. It'
Jennifer Messerly
2016/01/14 00:15:01
sent out a fix
|
| + var l0 = <dynamic /*=S*/>[x]; |
| + |
| + // but with regular constructors you can use it |
| + var l1 = new List/*<S>*/(); |
| + return l1; |
| +} |
| +``` |
| + |
| +## Instantiating generic methods |
| + |
| +Generic methods can be called without passing type arguments. Strong mode will |
| +attempt to infer the type arguments automatically. If it is unable to do so, |
| +then the type arguments will be filled in with whatever their declared bounds |
| +are (by default, `dynamic`). |
| + |
| +```dart |
| +class C { |
| + /*=S*/ inferableFromArgument/*<S>*/(/*=S*/ x) { return null;} |
| + /*=S*/ notInferable/*<S>*/(int x) { return null;} |
| +} |
| + |
| +void main() { |
| + C c = new C(); |
| + // This line will produce a type error, because strong mode will infer |
| + // `int` as the generic argument to fill in for S |
| + String x = c.inferableFromArgument(3); |
| + |
| + // This line will not produce a type error, because strong mode is unable |
| + // to infer a type and will fill in the type argument with `dynamic`. |
|
Bob Nystrom
2016/01/13 22:43:20
"no implicit dynamic" would yell here, I assume?
Jennifer Messerly
2016/01/13 22:49:33
Yup.
Aside: we're currently in a funny place with
|
| + String y = c.notInferable(3); |
| +} |
| +``` |
| + |
| +In the case that strong mode cannot infer the generic type arguments, the same |
| +syntax that was shown above for instantiating generic classes can be used to |
| +instantiate generic methods explicitly. |
| + |
| +```dart |
| +void main() { |
| + C c = new C(); |
| + // This line will produce a type error, because strong mode will infer |
| + // `int` as the generic argument to fill in for S |
| + String x = c.inferableFromArgument(3); |
| + |
| + // This line will produce a type error in strong mode, because `int` is |
| + // explicitly passed in as the argument to use for S |
| + String y = c.notInferable/*<int>*/(3); |
| +} |
| +``` |