-
Notifications
You must be signed in to change notification settings - Fork 27
Reify type in "generic" methods #301
Comments
Note however, there's another issue: reified tear offs: var list = <int>[1, 2, 3];
var mapper = list.map/*<String>*/; // (int -> String) -> Iterable<String>
var genericMapper = list.map; // <R>(int -> R) -> Iterable<R>
print(mapper((x) => '$x'));
// "int" would be inferred here, but assume we don't know that...
print(genericMapper/*<int>*/((x) => x + 42)); |
An issue: generic types can subtype non-generic ones, e.g. Also, a cleaner syntax like Two method names is the best I've been able to come up with, e.g. class B {
m(x, y) {
// ...
}
}
class D extends B {
m$([T = dynamic]) {
return (x, y) => {
// ...
};
}
}
D.prototype.m = D.prototype.m$();
function main() {
let d = new D();
d.m$(core.int)(1, 2);
d.m(1, 2);
} It's not very satisfying, though. We could symbolize: // ...
class D extends B {
[generic.m]([T = dynamic]) {
return (x, y) => {
// ...
};
}
}
D.prototype.m = D.prototype[generic.m]();
function main() {
let d = new D();
d[generic.m](core.int)(1, 2);
d.m(1, 2);
} Or use a string that is an illegal identifier in Dart (pretty much the same idea, but call should be faster by avoiding the symbol lookup): // ...
class D extends B {
['m<>']([T = dynamic]) {
return (x, y) => {
// ...
};
}
}
D.prototype.m = D.prototype['m<>']();
function main() {
let d = new D();
d['m<>'](core.int)(1, 2);
d.m(1, 2);
} Oh, there's also unicode characters. Can't say that any of these look great. Oh, and that's just for public members. Private ones need yet another scheme. |
There's another family of solutions, where we try and pass the type parameters as optional parameters. // ...
class D extends B {
// note, this won't actually work, because what if "T" is
// used later as a named parameter in a subtype.
// But something along these lines could work.
m(x, y, {T} = {T:dynamic}) => {
// ...
}
}
function main() {
let d = new D();
d.m(1, 2, {T: core.int});
d.m(1, 2);
} But that gets us into trouble with the already complex named & optional parameters. |
One thing to note, this problem won't come up for generic functions, or generic methods that don't override non-generic ones, or for other uses of universal function types: /*=T*/ g/*<T>*/(/*=T*/ t) = t;
Func1 f = g; // implicitly g/*<dynamic>*/ In that case, there's an implicit instantiation. We can generate code to instantiate it. I wonder if we'd be rejecting too much if we disallowed the generic-override-non-generic in strong mode. But those overrides do make sense in some cases, e.g.: class B {
Iterable map(f(x)); // (* -> *) -> Iterable<*>
}
class D extends B {
Iterable<T> map<T>(T f(x)); // <T>(* -> T) -> Iterable<T>
} |
For now I'm going to punt on the override-non-generic-with-generic case, and try to handle all of the "normal" cases. Split that out into #459 |
fyi, digging into this again. |
For methods we consider generic, we needs to instantiate the correct reified type.
E.g.,
should print
true
thenfalse
.An initial implementation will be based on whitelists/annotations of methods considered generic and inference at use sites.
See #300 for the static part and #28 for the general bug on generic methods.
The text was updated successfully, but these errors were encountered: