A value of type 'num' can't be assigned to a variable of type 'T'

10,009

Solution 1

The issue here is that Dart's new Null Safety feature, introduced in Dart 2.12.0, removed implicit downcasts from the language.

If res has type T where T extends num, then the operation res + something has static type num. The only thing we know about T is that it implements num, and num.operator+ returns num. However, num is not assignable to T extends num because the latter is a subtype of the former (T could be int, not all num values are assignable to int). So, you need an explicit cast to make the assignment valid:

res = (res + list[i]) as T;

is such a cast. If you just write res = res + list[i] as T;, the precedence of as means that it's the same as the cast above. In Dart 2.10.x, it worked without the explicit cast because the language inserted an implicit cast for you.

If you write res += list[i] as T; it instead means res = res + (list[i] as T); which is an unnecessary cast since list[i] already has type T, and doesn't cast the result of the addition.

The reason this doesn't fail all the time for int res = ...; res = res + otherInt; is that the language specification treats int.operator+ specially (along with some similar integer operators) and recognizes when the result is an integer, even if the + operator's return type is num. That special-casing does not apply to T extends num.

Solution 2

This appears to either be a bug or a misunderstood feature of Dart 2.12+. In either case, it might be worth opening an issue on the Dart Github page.

If I run the following code in 2.12.0:

void main() {
  final nums = [1, 2.0, 3.5];
  final ints = [1, 2, 3];
  final doubles = [1.1, 2.2, 3.3];
  
  sums(nums);
  sums(ints);
  sums(doubles);
}

void sums<T extends num>(List<T> list) {
  T res = list[0];
  for (var i = 1; i < list.length; i++) {
    res = res + list[i];
  }

  print(res);
}

I get the error you mentioned:

main.dart:14:9: Error: A value of type 'num' can't be assigned to a variable of type 'T'.
    res = res + list[i];
              ^

If, however, I run the same code in Dart 2.10.5, the program compiles and runs without a problem and I get the following printout:

6.5
6
6.6

My best guess is that there is an issue with type inference where the type parameter of the List is concerned. Instead of taking the actual type parameter passed to sums, it seems instead to be taking the type restraint num as its inferred type. As a result, the type system sees that you are adding a num to a T extends num and then assigning it to the latter. (To explain, imagine T is int. A num plus an int would result in a num. Trying to then assign that to an int results in a type error since, for all the type system knows, the num might actually be a double.)

At any rate, the error goes away once you do what the error suggests and cast the elements of list to T:

void sums<T extends num>(List<T> list) {
  T res = list[0] as T;
  for (var i = 1; i < list.length; i++) {
    res = res + list[i] as T;
  }

  print(res);
}

// Prints:
//
// 6.5
// 6
// 6.6

Interestingly, though, using an addition-assignment instead will cause the same error regardless of the cast:

void sums<T extends num>(List<T> list) {
  T res = list[0];
  for (var i = 1; i < list.length; i++) {
    res += list[i] as T;
  }

  print(res);
}

// Prints:
//
// main.dart:14:9: Error: A value of type 'num' can't be assigned to a variable of type 'T'.
//     res += list[i];
//         ^

EDIT: I've filed an issue for this topic on the Dart SDK Github page.


EDIT 2: Turns out this is not a bug but the result of an intended change to Dart as part of 2.12. See Irn's answer for details.

Share:
10,009

Related videos on Youtube

Muhammad Tawil
Author by

Muhammad Tawil

Updated on May 25, 2022

Comments

  • Muhammad Tawil
    Muhammad Tawil almost 2 years

    hello when i use this generic method i get this error

    A value of type 'num' can't be assigned to a variable of type 'T'. Try changing the type of the variable, or casting the right-hand type to 'T'.

    what the error here

    sums<T extends num>(List<T> list) {
      T res =list[0];
      for (var i = 1; i < list.length; i++) {
       res = res + list[i];
      }
      print(res);
    }
    
  • Muhammad Tawil
    Muhammad Tawil about 3 years
    yes , you are right !!! this issue was not found in previews version and hope that dart solve it .thank you so much your answer was helpful and solve it.