admin管理员组

文章数量:1303054

The following code compiles:

import 'dart:async';

void main() {
  final streamNullable = StreamController<int?>();
  final streamNotNullable = StreamController<int>();
  
  streamNullable.stream.pipe(streamNotNullable);
}

But will produce a runtime error:

TypeError: Instance of '_ControllerStream<int?>': type '_ControllerStream<int?>' is not a subtype of type 'Stream<int>'

... which is totally expected because we are trying to pipe nullable values into a non-nullable sink.

However, it surprises me that this doesn't cause a compile time error! Why didn't the type-system catch this?

As a side-note, this is only happening with a difference of the nullable-qualifier, not if I pass completely different types. For example:

final streamNullable = StreamController<int?>();
final streamNotNullable = StreamController<double>();
  
streamNullable.stream.pipe(streamNotNullable);

does not compile.

The following code compiles:

import 'dart:async';

void main() {
  final streamNullable = StreamController<int?>();
  final streamNotNullable = StreamController<int>();
  
  streamNullable.stream.pipe(streamNotNullable);
}

But will produce a runtime error:

TypeError: Instance of '_ControllerStream<int?>': type '_ControllerStream<int?>' is not a subtype of type 'Stream<int>'

... which is totally expected because we are trying to pipe nullable values into a non-nullable sink.

However, it surprises me that this doesn't cause a compile time error! Why didn't the type-system catch this?

As a side-note, this is only happening with a difference of the nullable-qualifier, not if I pass completely different types. For example:

final streamNullable = StreamController<int?>();
final streamNotNullable = StreamController<double>();
  
streamNullable.stream.pipe(streamNotNullable);

does not compile.

Share asked Feb 11 at 8:28 ph3rinph3rin 4,8961 gold badge22 silver badges45 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

That is an edge case in the lsp, to simplify it a bit, assume that null is not a type but the absence of an Object. Because the lsp is confined to dart code, native code and vm runtime definitions are outside of it's view and the lsp must assume that it 'just works' after passing the basic checks.

Can the lsp just be more strict?, no, the is check can't compare with null.

You can expect this behavior when a function is marked with external.

  int? a = 1;
  print('a is int - ${a is int}'); // warning - always true


  final sn = <int?>[null];

  Object v;
  v = List<num?>.from(sn);    // valid compile / valid runtime
  v = List<double?>.from(sn); // valid compile / valid runtime
  v = List<int>.from(sn);     // valid compile / runtime error
  v = List<num>.from(sn);     // valid compile / runtime error
  v = List<double>.from(sn);  // valid compile / runtime error

本文标签: