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); |
+} |
+``` |