Language: question: Method returning a generic type

Created on 30 Oct 2020  路  3Comments  路  Source: dart-lang/language

Hi everyone, I have this question, and it's really hurting my brain. I couldn't find an answer, and I hope that you give me one with as much detail as possible

why is it that I'm allowed to do this


void main(List<String> args) {
  print(foo<String>());
}

T foo<T>() {
  Object x = T == String ? "ok" : null;
  return x;
}

but not allowed to do this

void main(List<String> args) {
  print(foo<String>());
}

T foo<T>() {
  T x = T == String ? "ok" : null;
  return x;
}

what exactly is the difference between the two?

Thank you so much for helping me out :)

question

All 3 comments

The version with Object x = ... relies on an implicit downcast (from Object to T) in return x;. With the current version of Dart (before null safety), the downcast is allowed. It actually runs without errors at run time because null is allowed (before null safety) to be the value of an expression of any type, and the conditional ensures that the string literal is only used when T is String.

But the type system does not take T == String into account when it computes the types of expressions, so ... ? "ok" : null has type String (before null safety, and String? with null safety), no matter what ... stands for.

Hence, the version with T x = ... is rejected because there is no subtype relationship between the declared type (T) and the type of the initializing expression (String or String?).

With null safety, the version with Object? x = ... will have an error at return x;, because downcasts must be written explicitly. But you could change it to return x as T;.

I'll close the issue because it doesn't report anything that needs to change.

Thank you so much @eernstg this makes a lot of sense now. But one follow up question if I may.
so I understand that ... ? "ok" : null is going to be of type String or String? depending on null safety. But what about ... ? "ok" : 42 how does the type system determine the type of the expression in this case does it take into account ...?

Thank you so much for you answer I appreciate it a lot.

Thanks! With null safety, for an expression e of the form b ? e1 : e2, the static type of the expression is the least upper bound of the static type of e1 and e2. It never makes an attempt at understanding whether b might be guaranteed to be true or false, it just assumes that it could be either. But b might _show that some local variable has a specific type_, and that could be significant for the type of the expression as a whole:

void main() {
  dynamic d = 42;
  var x = d is int ? d : 0; // `x` has type `int`.
}

In this example, it is known in the true continuation of d is int that d has the type int, so the expression d in the true-branch of the conditional expression has type int; so does the false-branch 0; so the expression as a whole has type int.

The crucial difference is that this is a type test (e is T), which is significant to the type promotion machinery. But T == String is a comparison involving two instances of Type and an invocation of operator ==, and that's so far removed from the type system that it isn't taken into account when computing the type of an expression.

So ... ? "ok" : 42 will have the type Object (both with and without null safety), and given that neither "ok" nor 42 could ever be promoted, it doesn't depend on what ... stands for.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Cat-sushi picture Cat-sushi  路  3Comments

listepo picture listepo  路  3Comments

har79 picture har79  路  5Comments

creativecreatorormaybenot picture creativecreatorormaybenot  路  3Comments

leafpetersen picture leafpetersen  路  3Comments