dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.21k stars 1.57k forks source link

`MultiStreamController.onListen` is never called? #56925

Open sgrekhov opened 1 day ago

sgrekhov commented 1 day ago
import "dart:async";
import "../../../Utils/expect.dart";

main() {
  asyncStart(2);
  var stream = Stream<int>.multi((controller) {
    controller.onListen = () {
      print("onListen"); // Not printed
      asyncEnd();
    };
    controller.add(1);
    controller.add(2);
    controller.add(3);
    controller.close();
  });
  listen(stream);
  listen(stream);
}

void listen(Stream<int> stream) {
  int i = 0;
  stream.listen((v) {
    Expect.equals(++i, v);
  }, onDone: () {
    Expect.equals(3, i);
  });
}

According to the documentation "The callback which is called when the stream is listened to.". Why it is not called in the code above?

cc @lrhn

Dart SDK version: 3.7.0-27.0.dev (dev) (Tue Oct 15 17:02:51 2024 -0700) on "windows_x64"

dart-github-bot commented 1 day ago

Summary: The user is reporting that the onListen callback on a MultiStreamController is not being called when the stream is listened to, despite the documentation stating it should be. The provided code demonstrates the issue with two listeners on the same stream.

lrhn commented 1 day ago

This is documented on MultiStreamController. The Stream.multi constructor's onListen parameter is called when the stream is listened to, and the MultiStreamController is created at that point, as a controller for that particular steam subscription. Calling listen on the stream again creates a new controller.

Because of that, setting the onListen on the MultiStreamController has no effect, the one subscription that the controller applies to has already started listening.

Or, as an alternative view, the onListen argument is set as the onListen of a new MultiStreamController every time you listen to the Stream.multi stream, then that controller's stream is listened to instead, and the original stream listen returns that controller.

The code there is then, wrt. onListen, equivalent to a single subscription stream controller which sets onListen again inside its onListen function. The second value will never be called.

sgrekhov commented 5 hours ago

Thank you! This is documented not on MultiStreamController but on Stream.multi. IMHO it makes sense to document it on MultiStreamController and onListen as well.