language
language copied to clipboard
Syntax sugar to generate instance method tear-offs without an instance as closures
It's quite common to use a closure that takes a single parameter, and calls a single function on it.
For example, this pattern can be used to ensure that an API is only accessed in a safe manner:
class ApiService {
Future<Object> getData() { /* ... */ }
}
Future<T> callApi<T>(Future<T> Function(ApiService apiService) action) async {
try {
return await action(_apiService);
} on ApiException {
// ...
};
}
final data = callApi((apiService) => apiService.getData());
It would be great to be able to create the (apiService) => apiService.getData()
closure more concisely.
As static functions and instance functions cannot share names, the instance function could be automatically added as a static function, like so:
class MyClass {
void myInstanceFunction(Object a, Object b, Object c) {}
}
MyClass.myInstanceFunction; // (myObject, a, b, c) => myObject.myInstanceFunction(a, b, c);
That syntax may be a little confusing, though, as it adds a lot of duplicate functions - something like MyClass.methods.myInstanceFunction
could be done instead.
Maybe get some inspiration from Java with ::
so we can do: callApi(ApiService::getData())
where the ::
operator will be the same as creating: (ApiService apiService) => apiService.getData()
.
An argument against this, is that we can do this syntax shorter by just not provide a good name (or type) for the variable. So we could just shorten it into: callApi((s) => s.getData());
. But the cost is readability.
I often find myself wanting to write something like
var decks = [[1, 2, 3], [1, 2, 3], [1, 2, 3]];
decks.forEach(List.shuffle); // (List x) => x.shuffle()
An argument against this, is that we can do this syntax shorter by just not provide a good name (or type) for the variable. So we could just shorten it into: callApi((s) => s.getData());. But the cost is readability.
Another potential benefit to adding this language feature (though I'm not sure is technically possible) is for these generated closures to be used in const
expressions. This is currently not possible with a closure literal.
Or #265. Then it would be. e.g.,
final data = callApi(=> it.getData());