Skip to content

Syntax sugar to generate instance method tear-offs without an instance as closures #2349

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
hacker1024 opened this issue Jul 20, 2022 · 4 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@hacker1024
Copy link

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.

@hacker1024 hacker1024 added the feature Proposed language feature that solves one or more problems label Jul 20, 2022
@julemand101
Copy link

julemand101 commented Jul 20, 2022

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.

@Levi-Lesches
Copy link

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()

@hacker1024
Copy link
Author

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.

@lrhn
Copy link
Member

lrhn commented Jul 20, 2022

Or #265.
Then it would be. e.g.,

final data = callApi(=> it.getData());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

4 participants