Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime type error when using StreamTransformer-based APIs #683

Closed
Mike278 opened this issue Jun 28, 2022 · 3 comments · Fixed by #684
Closed

Runtime type error when using StreamTransformer-based APIs #683

Mike278 opened this issue Jun 28, 2022 · 3 comments · Fixed by #684

Comments

@Mike278
Copy link

Mike278 commented Jun 28, 2022

Repro:

import 'dart:async';

import 'package:rxdart/rxdart.dart';
// import 'package:stream_transform/stream_transform.dart';

void main() {
  Stream<String?>.value(null).mapNonNull(length).listen(print);
  Stream<String?>.value('a').mapNonNull(length).listen(print);
  Stream<String>.value('a').mapNonNull(length).listen(print);

  Stream<String?>.value(null).switchMapNonNull(length$).listen(print);
  Stream<String?>.value('a').switchMapNonNull(length$).listen(print);
  Stream<String>.value('a').switchMapNonNull(length$).listen(print);
  // ^ runtime error here:
  // type 'SwitchMapStreamTransformer<String?, int?>' is not a subtype of type 'StreamTransformer<String, int?>' of 'streamTransformer'
}

int length(String s) => s.length;
Stream<int> length$(String s) => Stream.value(s.length);

Stream<R?> _mapNonNull<T extends Object, R>(
  Stream<T?> stream,
  R? Function(T) mapper,
) {
  R? f(T? x) => x == null ? null : mapper(x);
  return stream.map<R?>(f);
}

Stream<R?> _switchMapNonNull<T extends Object, R>(
  Stream<T?> stream,
  Stream<R?> Function(T) mapper,
) {
  Stream<R?> f(T? x) => x == null ? Stream.value(null) : mapper(x);
  return stream.switchMap<R?>(f);
}

extension NullableStreamExtensions<T extends Object> on Stream<T?> {
  Stream<R?> mapNonNull<R>(R? Function(T) mapper) =>
      _mapNonNull<T, R>(this, mapper);

  Stream<R?> switchMapNonNull<R>(Stream<R?> Function(T) mapper) =>
      _switchMapNonNull<T, R>(this, mapper);
}
$ dart analyze bug.dart 
Analyzing bug.dart...
No issues found!
$ dart run bug.dart
Unhandled exception:
type 'SwitchMapStreamTransformer<String?, int?>' is not a subtype of type 'StreamTransformer<String, int?>' of 'streamTransformer'
#0      Stream.transform (dart:async/stream.dart)
#1      SwitchMapExtension.switchMap (package:rxdart/src/transformers/switch_map.dart:119:7)
#2      _switchMapNonNull ([...]bug.dart:34:17)
#3      NullableStreamExtensions.switchMapNonNull ([...]bug.dart:42:7)
#4      main ([...]bug.dart:13:29)
#5      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#6      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)

The error goes away if you swap the imports.

Reading up a bit on the issue indicates that this is due to Dart's covariant class generics. There are some sharp edges when it comes to classes that handle generics as both function arguments ("in" position) and return types ("out" position) or both - which is exactly what StreamTransformers do. Some relevant links:

@hoc081098
Copy link
Collaborator

hoc081098 commented Jun 28, 2022

I also had this issue

@Mike278
Copy link
Author

Mike278 commented Jun 28, 2022

See also: dart-lang/web_socket_channel#65, specifically

A recent change in the Dart SDK updated Socket to
implement Stream rather than Stream<List>.
This forwards compatible change calls StreamTransformer.bind()
rather than Stream.transform(), thus putting the stream in a
covariant position and allowing for the transition to Uint8List.

Following this approach, the error goes away if I replace return stream.switchMap<R?>(f); with return SwitchMapStreamTransformer<T?, R?>(f).bind(stream);

@hoc081098
Copy link
Collaborator

In mapNotNull and whereNotNull I have already used bind instead of transform. I will update others

@hoc081098 hoc081098 mentioned this issue Jun 30, 2022
hoc081098 added a commit that referenced this issue Jul 1, 2022
…m(StreamTransformer)` (#684)

Closes #683

* add nullable test for backpressure

* add nullable test for concat_with_test.dart

* to ignore_elements_test.dart

* to on_error_return_with_test.dart

* add tests

* bind

* add types

* changelog

* changelog

* changelog

* changelog

* changelog

* wip

* remove checkNotNull throttle

* add type windowTest
hoc081098 added a commit to hoc081098/rxdart_ext that referenced this issue Apr 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants