-
Notifications
You must be signed in to change notification settings - Fork 1.7k
use min/max instead of LUB/GLB in strong mode inference? #27917
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
Credit goes to @leafpetersen for this. I suspect it's a good change but from my quick test seems a bit more disruptive than expected. That said, our tests are likely pushing on it more than real code will. |
@nex3 found an interesting example of where this would be useful. Something like: expect<T>(T value, Matcher<T> matcher /*...*/) { /*...*/ } if I wrote code like this: test('confused', () {
expect(42, isTrue);
expect(123, equals(456.0));
}); ... those could be flagged as inference failures. |
See also dart-lang/test#2352. |
In my experience, there is almost an expectation that generic methods require exact matches. In fact, when you consider that most generic methods are emulating functional languages like haskell, and that in most of those languages the inferencing scheme allows at most let-bound polymorphism but usually no polymorphism at all, it makes sense to be completely strict on generic methods and let the user satisfy the type checker with casts. There are times where polymorpic inference for T is just fine, for instance, in fold. // List<T>.foldl<A>(A f(A acc, T item), A acc)
<int>[].foldl((x, y) => x + y), "A string accumumlator!"); When you use a string accumulator, it sets A to the LUB of "Object", and then "+" fails, so no surprises here. When you think about why, its because So maybe its best to not use LUB at all, but require an exact match, like this example will. To get deeper down the rabbit hole, in Here's a contravariant only example. // Sink<T> createAlternatingSink<T>(void consumerA(T), void consumerB<T>)
alternateConsumers((int x) => ..., (String y) => ...) Here, So it might be best to use exact type matches everywhere when inferring a type, not using LUB or GLB at all. You can always write And maybe, this is where I'm getting crazier, its best to use LUB only where there is no contravariant usage of the type. Because it essentially means, there's no guessable floor, and we're likely to go to |
C# requires an exact match, FWIW. |
Has anything changed here since the last update? |
We should close this. It's not happening for Dart 2 - very breaking. |
Strong mode inference for generics gathers constraints on the type (lower and upper bounds), and uses that to find a type that satisfies the bounds (in practice, it will pick either the lower or the upper). Right now, these bounds are computed using LUB and GLB as appropriate to combine constraints. But that causes us to synthesize a type that the user did not write down anywhere, not to mention depending on the LUB/GLB functions.
I tried a switch to min/max but it causes a lot of churn in tests, so I'd like to handle this as a separate issue from our other inference changes.
The text was updated successfully, but these errors were encountered: