-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Customer request: Wildcard generics #29777
Comments
Counter-example where my workaround breaks down: Map<K, V> pairs<K, V extends List<K>>(Map<K, V> from) => from;
void main() {
// OK. Customer does not want it to be OK.
var g = pairs({
1: [1, 2, 3],
'd': ['s']
});
g[44] = <String>['f'];
} |
As an aside, I don't think that in Java wildcards For Dart, would a more generalized typedef solve the problem? typedef Pairs<K> = Map<K, List<K>> For your counter-example: Dart generics are covariant, and we allow inference to take advantage of this. That is, we generate subtype constraints rather than equality constraints. On the plus side, this means that we can infer Map<K, List<K>> pairs<K>(Map<K, List<K>> from) => from;
void main() {
var g = pairs<int>({
1: [1, 2, 3],
'd': ['s'] // Error
});
g[44] = <String>['f'];
} |
The desired behavior I was thinking of was: void main() { g[44] = ['f']; //should error And thinking further, I'm not sure this is actually doable in Java. Although wildcards or use-site variance would be nice to have in Dart |
Yeah, this strikes me as an interesting request, but I think you can do it if you're willing to give up map syntax. The problem is that I'm not sure if this can really be expressed as part of the generic itself, because the K and V for maps would be related in different ways. For some Map you're constraining to String pairs, or Int pairs:
I think you would fundamentally have to control the definition of Map to do this. Luckily, you can, if you are willing to give up map literals:
you can also define a
and you can override
then initialize with
but unfortunately, not with
or anything like that. And, of course, Hmm, and thinking about it more, you have an issue where
will not have a type error, because it infers |
I think in @MichaelRFairhurst's code First class existentials kind of get you something like what you want. Since Dart 2.0 has first class universals, you can actually define a type that corresponds to: // Not really Dart
typedef LinkedPair = Exists<T>.Pair<T, List<T>> and then use an association list of LinkedPair objects instead of a map, or else use a map from keys to LinkedPair values, with the invariant that the first element of the LinkedPair is the same as the key, but that seems pretty convoluted. So yeah, I'd say define a class. |
It's true that Java wildcards will not enforce the constraint that this customer wants ('Customer does not want it to be OK'). The point is that it would always be possible to create the relevant pair (for a What you are asking for is basically a guarantee that your pair has type arguments which are exactly the run-time types of the key and value in that pair. But we do not have the notion of constraining the run-time type of an object to be equal to a type annotation (that is, 'exact types') rather than having a subtype thereof. Note that even an existential type is insufficient for that: It is also true that the two occurrences of void foo(List<X> xs) { X x; ... }
List<?> myList;
foo(myList); However, that's not allowed when it gives the same name to multiple So wildcards and existentials won't do it without exactness. Conversely, if you have exactness then you don't need the other two features (I'm just assuming that we write a data structure from scratch here; we can't impose the typing structure on an existing class like class ElementToListPair<K> {
exact K key;
ExactList<K> value; // A list whose elements are exactly of type K.
}
class ElementToListMap<K> { ... } For this to work, any method on class HoldPairs<T> {
ExactSet<T> elements;
ExactSet<ExactList<T>> lists;
} We could now use some instances of This means that we can maintain the precise relationship between each (element, list) pair in the map, and at the same time we are using normal subtype subsumption (and generic class covariance) to abstract away the precise dependency on which types it is that we are keeping under such tight control. It could be However, exactness will obviously propagate far away from the location where you wished to have it in the first place, and it quickly gets verbose and inconvenient. It's even difficult to introduce generically: It may be possible to invent some clever technique such that we can express In summary, it wouldn't be impossible to introduce language support for maintaining a discipline of the kind that this customer wants, but it's heavy .. and not likely to happen. |
This has come up a few times internally, mostly in the context of contravariant function types. |
Considering the title at first, the topic of wildcard generics is essentially covered by statically checked variance: Declaration-site variance in dart-lang/language#524, and use-site variance in dart-lang/language#753. So in that sense this issue is already a duplicate. However, as the discussion above shows, Java style wildcarded types cannot be used to satisfy all the requirements that have been mentioned in this issue. In particular, the interplay between subtyping and type inference implies that The generalized typedef doesn't really make any difference, as far as I can see. So the situation is that this issue raises all kinds of interesting type system considerations (and in that sense it is not resolved at all), but the topic (according to the title) is already covered pretty well elsewhere, and the discussions haven't produced anything really concrete and useful for Dart right now. So I'll close the issue. To anyone who thinks that there is a line of thinking in this issue that needs to be further developed: Please create a new issue on that, in the language repository! ;-) |
Appreciate the summary, I better understand the issue now. Thanks. |
Source: Wildcard (Java).
An internal customer wanted to make sure they had bound generics when creating pairs.
Example
Workaround
See DartPad:
Make sure to enable strong mode.
The text was updated successfully, but these errors were encountered: