Abitofevrything
Abitofevrything

Reputation: 24

Dart perform runtime subtype checking

I would like to perform runtime subtype checking in Dart without using dart:mirrors.

What I mean by this is that given two types A and B, either as variables with type Type or as type arguments on a generic class (i.e the variables being checked would be, using List as a dummy class, List<A> and List<B>), I would like to check if A is a subtype of B.

Here is some code written with dart:mirrors that performs what I want:

bool isSubtype(Type a, Type b) => reflectType(a).isSubtypeOf(reflectType(b));

// OR

bool isSubType<A, B>(List<A> a, List<B> b) => reflect(a).type.typeArguments[0].isSubtypeOf(reflect(b).type.typeArguments[0]);

I would like to perform this check without using dart:mirrors. I have tried using the following code:

bool isSubType<A, B>(List<A> a, List<B> b) => <A>[] is List<B>;

However, while this code works with expressions with a static type:

print(isSubType(<Iterable>[], <Iterable>[])); // true
print(isSubType(<Iterable>[], <List>[]));     // true
print(isSubType(<Iterable>[], <String>[]));   // false

it does not work with expressions without a static type:

List a = <Iterable>[];

List<List> types = [<Iterable>[], <List>[], <String>[]];

for (final type in types) {
  print(isSubType(type, a)); // true, true, true
}

How can I implement isSubType to get the correct result for types that are unknown at compile-time?

Note: I don't need this to be compatible with the JS runtime, just AOT and JIT compiled Dart.

Upvotes: 0

Views: 345

Answers (1)

lrn
lrn

Reputation: 71603

If all you want is to chcek the subtype relation of two types, you don't need arguments at all, only type arguments.

bool isSubtype<S, T>() => <S>[] is List<T>;

You also can't extract the runtime type of an object as a type argument. I'm guessing that's what you are trying to do with the arguments and type inference, but type inference happens at compile-time and only uses the static types of the arguments. The call print(isSubType(type, a)) infers the type List<dynamic> for both type arguments from the expressions type and a, and does so at compile-time and independently of the actual run-time type that variable will contain.

There is no general way, outside of dart:mirrors, to check whether two objects have runtime types that are related to each other, because it's not possible to get the runtime type of an object into a type variable.

You also can't do anything similar with Type objects. A Type object is only really good for passing into dart:mirrors, and maybe compare for equality. It doesn't understand subtyping at all.

Upvotes: 3

Related Questions