-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Support a type for "function that returns T" #26420
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
Comments
I know @eernstg has suggested I'm still a little concerned that it's only half of a general solution. If you can take one of six function types, maybe you would be better off with a union type so you actually specify the allowed arguments too, and not just the return type. About void functions: It would be great if "void" could be used as a type parameter as well. It would mean it could be used as a type in general. It might not make sense in a lot of places (at least not with non-nullable types), but it's more orthogonal if |
It is half a solution in the sense that it skips over the parameter list shape and the associated types, but the situation isn't symmetric: (1) Knowledge about the return type is significant for lookups, and without that type (along with suitable runtime guarantees such that we can trust it) we have no knowledge about the nominal identity of the looked-up member. Without the return type for (2) Knowledge about the parameter list shape and the parameter types is less tricky in relation to software correctness because it can be checked directly: If you get it wrong (and suitable runtime checks are active) then you'll get a clear message at the invocation. You are not going to go ahead and perform some completely unintended action that happens to have the same name. That was my main motivation for recommending |
The return type is also significant for |
Very good, so we have lots of reasons for introducing |
I must be missing something, but this code prints "true" and "false", as well as reports
Why do we need special support for return types? typedef int F();
int foo() => 0;
String bar() => '';
void useF(F f) {}
void useF2(int f()) {}
main() {
print(foo is F);
print(bar is F);
useF(foo);
useF(bar);
useF2(foo);
useF2(bar);
} |
You could argue that we cannot abstract over formal parameter list shapes, but it is at least possible to abstract over functions that accept k positional arguments (so the argument list declares at least k positional arguments, and it does not declare m > k required positional arguments) using definitions like typedef T Func0<T>();
...
typedef T Func3<T>(Object x1, Object x2, Object x3);
... up to some fixed maximal number N. I could have left out the argument types, but the plain If you wish to wrap a given first class function such that the resulting wrapper function can be used in the context where the wrappee is expected then you must ensure that the wrapper has a reified type which will pass the (strong mode or Dart 2.0) checks intended for the wrappee. For any positional argument type in the wrappee we can use If we could pass the return type along (by using (The actual code for So we need special support for return types because we cannot provide a type "that will always work" in a covariant position, as opposed to contravariant positions where |
Following up here based on some discussion off of the issue tracker. It looks to me like that there is not broad support for the kind of language changes that could address this in the short term, but rather a preference for one of several more general options that won't be available soon. I see this as leaving us as two options for the short term:
Function expectAsync<T>(Function f, ...) {... }
Callback<int, int> f = expectAsync<int>((int x) => x) as Callback<int, int>;
F expectAsync0<T, F extends Callback0<T>>(T f()) => ...
F expectAsync1<T, F extends Callback1<dynamic, T>(T f(dynamic x)) => ...
...
Callback<int, int> f = expectAsync1((int x) => x); Option 1 has the advantage that the API for non-strong mode stays the same, but it has the disadvantage that you get no static checking. If you don't pass a type argument, or if you pass the wrong one, you will get no static error, but you will get a runtime error in DDC. Option 2 gives better static checking at the expense of a breaking change to the API. |
On Tue, Nov 1, 2016 at 12:40 AM, Leaf Petersen [email protected]
I can't find anything smarter than that. Even by using configured imports to have a DDC specific version, I can't /LLasse R.H. Nielsen - [email protected]
On Tue, Nov 1, 2016 at 12:40 AM, Leaf Petersen [email protected]
Lasse R.H. Nielsen - [email protected]
|
@leafpetersen - any updates? |
We do not plan to add Details here: dart-lang/test#436 @floitschG is driving this. |
Closing as not planned in favor of proposed changes to the expectAsync API. |
Right now, there's no way to use Dart's type syntax to express a constraint on the return type of a function without also expressing constraints on its arguments. This makes it impossible to make certain classes of first-class functions strong-mode compatible.
The most notable function that needs this
expectAsync()
intest
, which is widely used when testing asynchronous code. It takes a function (with up to six arguments and no named arguments) and returns a wrapper function with a compatible signature and some extra logic. In order to work with strong mode, it needs the output function to have a reified return type that matches the input function's, but there's no way to do that right now.I propose that we add a generic parameter to
Function
representing its return type. That way we could writeexpectAsync()
like so:I'm marking this as S1 because it will be a barrier to the use of DDC with the
test
package once support for that exists (dart-lang/test#414).The text was updated successfully, but these errors were encountered: