Channel Directions in Dart

In Dart, we can use Stream and StreamController to mimic the behavior of channels. While Dart doesn’t have built-in channel direction specifications like Go, we can achieve similar functionality using StreamController and StreamSink.

import 'dart:async';

// This `ping` function only accepts a StreamSink for sending
// values. It would be a runtime error to try to receive on this sink.
void ping(StreamSink<String> pings, String msg) {
  pings.add(msg);
}

// The `pong` function accepts one Stream for receives
// (`pings`) and a StreamSink for sends (`pongs`).
void pong(Stream<String> pings, StreamSink<String> pongs) async {
  String msg = await pings.first;
  pongs.add(msg);
}

void main() async {
  final pingsController = StreamController<String>();
  final pongsController = StreamController<String>();

  ping(pingsController.sink, "passed message");
  pong(pingsController.stream, pongsController.sink);

  print(await pongsController.stream.first);

  // Close the controllers to prevent memory leaks
  await pingsController.close();
  await pongsController.close();
}

To run the program:

$ dart run channel_directions.dart
passed message

In this Dart version:

  1. We use StreamController to create streams that act like channels.
  2. The ping function takes a StreamSink which only allows adding elements (sending).
  3. The pong function takes a Stream for receiving and a StreamSink for sending.
  4. In the main function, we create two StreamControllers to manage our streams.
  5. We use controller.sink for sending and controller.stream for receiving.
  6. The async and await keywords are used to handle asynchronous operations.
  7. We close the controllers at the end to prevent memory leaks.

While Dart doesn’t have the same compile-time channel direction checks as Go, this approach provides similar functionality and type safety at runtime.