dart-lang / dart-lang/language
Abbreviated formal parameter lists using `forward`
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
In response to #57, we might be able to use a keyword like `forward` to specify that a given declaration of a function contains abbreviated or omitted formal parameter lists, and it is not doing anything else than passing its arguments on without changes to some other function.
```dart
void f(int foo, String bar, {bool baz = true}) {...}
// The next declaration is an abbreviation of
// `void g(int foo, String bar, {bool baz = true}) => f(foo, bar, baz: baz);`
forward g = f;
```
This would be applicable to library functions, static methods, instance methods, and local functions, including getters and setters and operators, and it would also be applicable to constructors.
For constructors, however, we will often have a situation where initializing formals can be used to accept some additional arguments, and hence we'd want to specify a _partial_ formal parameter list, and then use something similar to the forwarding abbreviation for all the remaining arguments, which will then be declared and forwarded implicitly.
```dart
// Variant of example from #57 from Mouad Debbar.
class Base {
final int foo;
final String bar;
final bool baz;
Base({this.foo, this.bar, this.baz});
}
class Sub1 extends Base {
// The next declaration is an abbreviation of
// `Sub1({int foo, String bar, bool baz}): super(foo: foo, bar: bar, baz: baz);`
forward Sub1 = super;
}
class Sub2 extends Base {
final Map myBar; // Additional feature: Allow for extra arguments.
// The next declaration is an abbreviation of
// `Sub2({int foo, String bar, bool baz, this.myBar}): super(foo: foo, bar: bar, baz: baz);`
forward Sub2({this.myBar}) = super;
}
```
For constructors, it is easy to define the semantics of adding a named parameter or a positional parameter to a given statically known formal parameter list (and raise an error if we try to add a named parameter to a formal parameter list that already has an optional positional parameter, or vice versa, or if we try to add a required parameter to a formal parameter list that already has one or more optional parameters).
The semantics would in all cases be that the new formal parameters are added at the end of the existing formal parameter list, and that may succeed or it may be an error.
Partial formal parameter lists are more tricky in the case where we are forwarding to an instance method, or the forwarding declaration has a target which is a first class function object. First, we have no notion like 'initializing formals', so it is likely to be a useless feature to be able to add more parameters (they will always be ignored anyway). But it might be useful in order to create wrappers for functions that manipulate their type a little bit (so we must deliver a `Function({bool b})`, and we have a function `f` of type `Function()`, but then we just declare a local forwarder `forward g({bool b}) = f;`).
```dart
// This could be useful. We avoid declaring a complex signature for `f`.
forward f = complexExpressionComputingAFunction;
// This is probably not useful, `y` is simply discarded. It would only be useful
// in cases where, say, complexExpression2 has type `Function(int)` and we
// need a function of type `Function(int, String)`, and it's OK that it ignores its
// second argument.
forward g(String y) = complexExpression2;
abstract class A {
void f(int x);
// It's probably not very useful to allow an instance method
// forwarder to take extra arguments.
forward g(String y) = f; // `y` is simply discarded.
}
```
This seems to imply that the partial formal parameter lists are rather easy to handle in the static case, and they are not very useful in the case where function type subtyping may occur. So we should probably just have then for the static case, and most likely only for constructors.
Contributor guide
Assessment
This issue has not been assessed yet.