You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: working/union-types/nominative-union-types.md
+17-1Lines changed: 17 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -35,7 +35,7 @@ It’s a subtype of `Object` if all the elements types are subtypes of `Object`.
35
35
36
36
If `F` is nullable, then `F?` is equivalent to `F` (mutual subtypes), otherwise `F?` is a proper supertype of `F`.
37
37
38
-
The type is a supertype of each of its union element types (`Foo` is a supertype of `A` and `B` here.).
38
+
The type is a supertype of each of its union element types (`F` is a supertype of `T1` .. `Tn` here.).
39
39
40
40
If the union type is generic, different instantiations can be subtypes of each other. The type parameters vary by their occurrences, like for a type alias. For example `typedef Foo<T> = T Function(int) | int Function(T);` is invariant in `T` because `T` occurs both covariantly and contravariantly in the union element types. _(This might need us to introduce variance first.)_. For `typedef G<X> = List<X> | Set<X>;`, `G<int>` is a subtype of `G<num>`, because `X` occurs only covariantly, so `G` varies covariantly with `X`. _A direct use of the type variable, like `typedef U<S, T> = S | T;` counts as covariant._
41
41
@@ -127,6 +127,22 @@ In every other way, the union type is just a normal type, with the subtype relat
127
127
128
128
## Limitations and discussions
129
129
130
+
### The subtying rules don't actually *work*
131
+
132
+
if you have `abstract class C implements List<C> {}` and want to check whether `C` is a subtype of `Json`, as defined above,
133
+
then you eventually have to try checking whether `C` is a subtype of `List<Json>`. Since `C` is a `List<C>`, all you need to
134
+
check is whether `C` is a subtype of `Json`. Whoops.
135
+
136
+
Which means that we probably need to prevent *any* cyclic references in the union types, which again makes them much less
137
+
useful for actual recursive types like `Json`.
138
+
139
+
We can declare classes for such a structure, for example sealed classes like `sealed class Json {}`, `class JsonValue<T> extends Json { T get value; }`, `class JsonList extends Json implements List<Json>` and `class JsonMap extends Json implements Map<String, Json>`.
140
+
That's not the same. Checking whether something is a `Json` is simple, the object itself knows that. Whether it's a `JsonList` too.
141
+
For the union `Json` type, there really is an infinite number of different subtypes that we need to potentially check for in order to determine whether a value belongs to the set of accepted values.
142
+
The new type introduced is not a type that any object *inherently* implements.
143
+
144
+
(Should we drop the subtyping, and only have assignability into the union type? No type relations between union types and non-union types other than `Never`, `Object` or `Object?`? Then a `List<C>` is-not-a `List<Json>` and vice-versa. And a `List<int>` is not a `List<Json>` either, only `List<Json>` itself is. Much more restricted, definitely.)
145
+
130
146
### Incompatible with existing `dynamic`-using types
131
147
132
148
This does not allow having a simple type alias for existing JSON values,
0 commit comments