andras
andras

Reputation: 3645

Dart 2 runtimeType and reified generics - Java Class<T> equivalent

I am having trouble understanding how generics in Dart work and the documentation did not help me sadly.


If I make a class called Checker that needs to store it's generic params in some way, I could do it this way (since Dart has reified generics):

class A {}

class B extends A {}

class Checker<T> {
  bool test(dynamic a) {
    return a is T;
  }
}

main() {
  print(Checker<A>().runtimeType);
  print(Checker<B>().runtimeType);
  print(Checker<String>().runtimeType);

  print(Checker<A>().test(A()));
  print(Checker<A>().test(B()));
  print(Checker<A>().test(""));
}

This prints out, just as you would expect:

Checker<A>
Checker<B>
Checker<String>
true
true
false

Here is the issue:

class A {}

class B extends A {}

class Checker<T> {
  bool testChecker<C>(Checker<C> a) {
    return C is T;
  }
}

The output:

false
false
false

It seems like, that two reified generics do not work well with each other.

In Java, this is mostly solved by storing a Class<T>, which has isAssignableFrom function that does what it says. In Dart, the Type is only an empty abstract class, so there is no use in reading/storing the runtimeType, because there is no function to call on it to check assignability relationships. (Edit.: All classes returned by runtimeType are of type _Type, so none of their methods can be called.)

How can I save runtimeType in Dart?

Upvotes: 3

Views: 1034

Answers (1)

lrn
lrn

Reputation: 71623

If you change testChecker to return a is Checker<T>;, would that be enough for you? That would be checking the runtime type of a, not the static type of it at the call-point. If you want the latter, you can do return new Checker<C>() is Checker<T>;.

It is correct that you should never use Type objects for anything like this, so .runtimeType is not useful.

The reason the example didn't work was that it did return C is T;. The is operator takes an object on the left and a type on the right. So, C is evaluated as an object, which means it evaluates to an object of type Type. Then it checks whether Type is a subtype of T, which it isn't. You can't compare type variables directly, you have to compare objects to types. One option is to do <C>[] is List<T> - that is: Check that a ist of C (object) is-a list of T (type). Since I already had a generic class available, I just used Checker<C>() is Checker<T> instead.

Upvotes: 2

Related Questions