Problem with generic types which extends from num and type cast from int to double

I have a question regarding generics in dart. I have the following dart code with a generic type parameter which extends num. In my class I want now to define a variable from type T with value zero. This seems to be not possible. Can anyone explain me why this is the case?

class A<T extends num> {
  T t = 0; // error: A value of type 'int' can't be assigned to a variable of type 'T'.
  num n = 0; // works 
}

The problem I am facing is that I want to create a list in my class initialized with zeros. So I can do:

A() {
 var list = List<T>.filled(10, 0 as T)
}

which works for A<int>() but it fails for A<double>() with the error message

type 'int' is not a subtype of type 'double' in type cast

Whats confusing because since Dart 2.1 it's possible to pass an int to a double variable like:

double x = 0;

So how can I solve this? Is the only option really to do a type check in my constructor and generate the list with 0 or 0.0 depending on T's type?

3 answers

  • answered 2020-11-25 07:15 Randal Schwartz

    Use an actual double 0.0, not 0.

  • answered 2020-11-25 07:36 ChessMax

    The easiest fix is to add a zero value to a constructor. Something like that:

    class A<T extends num> {
      final T zero;
      A(this.zero) : assert(zero != null) {        
        var list = List<T>.filled(10, zero);
      }
    }
    

  • answered 2020-11-25 09:58 lrn

    There is no simple expression which can evaluate to either 0 or 0.0 based on what T is bound to at run-time. The type of an expression in Dart is determined at compile-time, and you don't know the actual type of T before run-time.

    What you can do is:

    T t = 0.0 is T ? (0.0 as T) : (0 as T);
    

    If someone manages to create a T<Never>, then one of those casts will throw, which is probably what you want.

    If you have any other value of type T, then you can do:

    class A<T extends num> {
      T t;
      A(T someValue) : t = (someValue * 0) as T;
    }
    

    Generally, Dart generics (type parameters) are intended for classes which treat values of the type parameter types generically, the same independently of what the type argument is. What you're trying to do here is type specialization, not being type generic, which is why you don't have language support for it.

    You'd probably be better off making ANum, AInt and ADouble classes and creating the one you want - then you also don't have to worry about A<Never> (or A<Null> pre-null-safety).