Dart What does “StreamTransformer cast()” do?











up vote
0
down vote

favorite












I've implemented the stream transformer. Please note that it is only an exercise (in order to learn Dart). This transformer converts integers into strings. I give the code below, and you can also find it on GitHub.



// Conceptually, a transformer is simply a function from Stream to Stream that
// is encapsulated into a class.
//
// A transformer is made of:
// - A stream controller. The controller provides the "output" stream that will
// receive the transformed values.
// - A "bind()" method. This method is called by the "input" stream "transform"
// method (inputStream.transform(<the stream transformer>).

import 'dart:async';

/// This class defines the implementation of a class that emulates a function
/// that converts a data with a given type (S) into a data with another type (T).
abstract class TypeCaster<S, T> {
T call(S value);
}

/// This class emulates a converter from integers to strings.
class Caster extends TypeCaster<int, String> {
String call(int value) {
return "<${value.toString()}>";
}
}

// StreamTransformer<S, T> is an abstract class. The functions listed below must
// be implemented:
// - Stream<T> bind(Stream<S> stream)
// - StreamTransformer<RS, RT> cast<RS, RT>()

class CasterTransformer<S, T> implements StreamTransformer<S, T> {

StreamController<T> _controller;
bool _cancelOnError;
TypeCaster<S, T> _caster;

// Original (or input) stream.
Stream<S> _stream;

// The stream subscription returned by the call to the function "listen", of
// the original (input) stream (_stream.listen(...)).
StreamSubscription<S> _subscription;

/// Constructor that creates a unicast stream.
/// [caster] An instance of "type caster".
CasterTransformer(TypeCaster<S, T> caster, {
bool sync: false,
bool cancelOnError: true
}) {
_controller = new StreamController<T>(
onListen: _onListen,
onCancel: _onCancel,
onPause: () => _subscription.pause(),
onResume: () => _subscription.resume(),
sync: sync
);
_cancelOnError = cancelOnError;
_caster = caster;
}

/// Constructor that creates a broadcast stream.
/// [caster] An instance of "type caster".
CasterTransformer.broadcast(TypeCaster<S, T> caster, {
bool sync: false,
bool cancelOnError: true
}) {
_cancelOnError = cancelOnError;
_controller = new StreamController<T>.broadcast(
onListen: _onListen,
onCancel: _onCancel,
sync: sync
);
_caster = caster;
}

/// Handler executed whenever a listener subscribes to the controller's stream.
/// Note: when the transformer is applied to the original stream, through call
/// to the method "transform", the method "bind()" is called behind the
/// scenes. The method "bind()" returns the controller stream.
/// When a listener is applied to the controller stream, then this function
/// (that is "_onListen()") will be executed. This function will set the
/// handler ("_onData") that will be executed each time a value appears
/// in the original stream. This handler takes the incoming value, casts
/// it, and inject it to the (controller) output stream.
/// Note: this method is called only once. On the other hand, the method "_onData"
/// is called as many times as there are values to transform.
void _onListen() {
_subscription = _stream.listen(
_onData,
onError: _controller.addError,
onDone: _controller.close,
cancelOnError: _cancelOnError
);
}

/// Handler executed whenever the subscription to the controller's stream is cancelled.
void _onCancel() {
_subscription.cancel();
_subscription = null;
}

/// Handler executed whenever data comes from the original (input) stream.
/// Please note that the transformation takes place here.
/// Note: this method is called as many times as there are values to transform.
void _onData(S data) {
_controller.add(_caster(data));
}

/// This method is called once, when the stream transformer is assigned to the
/// original (input) stream. It returns the stream provided by the controller.
/// Note: here, you can see that the process transforms a value of type
/// S into a value of type T. Thus, it is necessary to provide a function
/// that performs the conversion from type S to type T.
/// Note: the returned stream may accept only one, or more than one, listener.
/// This depends on the method called to instantiate the transformer.
/// * CasterTransformer() => only one listener.
/// * CasterTransformer.broadcast() => one or more listener.
Stream<T> bind(Stream<S> stream) {
_stream = stream;
return _controller.stream;
}

// TODO: what should this method do ? Find the answer.
StreamTransformer<RS, RT> cast<RS, RT>() {
return StreamTransformer<RS, RT>((Stream<RS> stream, bool b) {
// What should we do here ?
});
}
}


main() {

// ---------------------------------------------------------------------------
// TEST: unicast controller.
// ---------------------------------------------------------------------------

// Create a controller that will be used to inject integers into the "input"
// stream.
StreamController<int> controller_unicast = new StreamController<int>();
// Get the stream "to control".
Stream<int> integer_stream_unicast = controller_unicast.stream;
// Apply a transformer on the "input" stream.
// The method "transform" calls the method "bind", which returns the stream that
// receives the transformed values.
Stream<String> string_stream_unicast = integer_stream_unicast.transform(CasterTransformer<int, String>(new Caster()));

string_stream_unicast.listen((data) {
print('String => $data');
});

// Inject integers into the "input" stream.
controller_unicast.add(1);
controller_unicast.add(2);
controller_unicast.add(3);

// ---------------------------------------------------------------------------
// TEST: broadcast controller.
// ---------------------------------------------------------------------------

StreamController<int> controller_broadcast = new StreamController<int>.broadcast();
Stream<int> integer_stream_broadcast = controller_broadcast.stream;
Stream<String> string_stream_broadcast = integer_stream_broadcast.transform(CasterTransformer<int, String>.broadcast(new Caster()));

string_stream_broadcast.listen((data) {
print('Listener 1: String => $data');
});

string_stream_broadcast.listen((data) {
print('Listener 2: String => $data');
});

controller_broadcast.add(1);
controller_broadcast.add(2);
controller_broadcast.add(3);
}


The class CasterTransformer<S, T> extends the abstract class StreamTransformer<S, T>.



Thus, it implements the method StreamTransformer<RS, RT> cast<RS, RT>().



On the documentation, it is said that :




The resulting transformer will check at run-time that all data events of the stream it transforms are actually instances of S, and it will check that all data events produced by this transformer are actually instances of RT.




See: https://api.dartlang.org/stable/2.1.0/dart-async/StreamTransformer/cast.html



First, I think that there is a typo in this documentation : it should say "...it transforms are actually instances of RS" (instead of S).



However, this seems obscure to me.




  • Why do we need a stream transformer to check values types ? The purpose of a transformer is to transform, isn't it ? If the purpose of a component is to check, so why don't we call it a checker ?

  • And, also, why would we need to check that the transformer (we implement) produces the required data ? If it doesn't, then we face a bug that should be fixed.


Can someone explain the purpose of the method Cast() ?










share|improve this question




























    up vote
    0
    down vote

    favorite












    I've implemented the stream transformer. Please note that it is only an exercise (in order to learn Dart). This transformer converts integers into strings. I give the code below, and you can also find it on GitHub.



    // Conceptually, a transformer is simply a function from Stream to Stream that
    // is encapsulated into a class.
    //
    // A transformer is made of:
    // - A stream controller. The controller provides the "output" stream that will
    // receive the transformed values.
    // - A "bind()" method. This method is called by the "input" stream "transform"
    // method (inputStream.transform(<the stream transformer>).

    import 'dart:async';

    /// This class defines the implementation of a class that emulates a function
    /// that converts a data with a given type (S) into a data with another type (T).
    abstract class TypeCaster<S, T> {
    T call(S value);
    }

    /// This class emulates a converter from integers to strings.
    class Caster extends TypeCaster<int, String> {
    String call(int value) {
    return "<${value.toString()}>";
    }
    }

    // StreamTransformer<S, T> is an abstract class. The functions listed below must
    // be implemented:
    // - Stream<T> bind(Stream<S> stream)
    // - StreamTransformer<RS, RT> cast<RS, RT>()

    class CasterTransformer<S, T> implements StreamTransformer<S, T> {

    StreamController<T> _controller;
    bool _cancelOnError;
    TypeCaster<S, T> _caster;

    // Original (or input) stream.
    Stream<S> _stream;

    // The stream subscription returned by the call to the function "listen", of
    // the original (input) stream (_stream.listen(...)).
    StreamSubscription<S> _subscription;

    /// Constructor that creates a unicast stream.
    /// [caster] An instance of "type caster".
    CasterTransformer(TypeCaster<S, T> caster, {
    bool sync: false,
    bool cancelOnError: true
    }) {
    _controller = new StreamController<T>(
    onListen: _onListen,
    onCancel: _onCancel,
    onPause: () => _subscription.pause(),
    onResume: () => _subscription.resume(),
    sync: sync
    );
    _cancelOnError = cancelOnError;
    _caster = caster;
    }

    /// Constructor that creates a broadcast stream.
    /// [caster] An instance of "type caster".
    CasterTransformer.broadcast(TypeCaster<S, T> caster, {
    bool sync: false,
    bool cancelOnError: true
    }) {
    _cancelOnError = cancelOnError;
    _controller = new StreamController<T>.broadcast(
    onListen: _onListen,
    onCancel: _onCancel,
    sync: sync
    );
    _caster = caster;
    }

    /// Handler executed whenever a listener subscribes to the controller's stream.
    /// Note: when the transformer is applied to the original stream, through call
    /// to the method "transform", the method "bind()" is called behind the
    /// scenes. The method "bind()" returns the controller stream.
    /// When a listener is applied to the controller stream, then this function
    /// (that is "_onListen()") will be executed. This function will set the
    /// handler ("_onData") that will be executed each time a value appears
    /// in the original stream. This handler takes the incoming value, casts
    /// it, and inject it to the (controller) output stream.
    /// Note: this method is called only once. On the other hand, the method "_onData"
    /// is called as many times as there are values to transform.
    void _onListen() {
    _subscription = _stream.listen(
    _onData,
    onError: _controller.addError,
    onDone: _controller.close,
    cancelOnError: _cancelOnError
    );
    }

    /// Handler executed whenever the subscription to the controller's stream is cancelled.
    void _onCancel() {
    _subscription.cancel();
    _subscription = null;
    }

    /// Handler executed whenever data comes from the original (input) stream.
    /// Please note that the transformation takes place here.
    /// Note: this method is called as many times as there are values to transform.
    void _onData(S data) {
    _controller.add(_caster(data));
    }

    /// This method is called once, when the stream transformer is assigned to the
    /// original (input) stream. It returns the stream provided by the controller.
    /// Note: here, you can see that the process transforms a value of type
    /// S into a value of type T. Thus, it is necessary to provide a function
    /// that performs the conversion from type S to type T.
    /// Note: the returned stream may accept only one, or more than one, listener.
    /// This depends on the method called to instantiate the transformer.
    /// * CasterTransformer() => only one listener.
    /// * CasterTransformer.broadcast() => one or more listener.
    Stream<T> bind(Stream<S> stream) {
    _stream = stream;
    return _controller.stream;
    }

    // TODO: what should this method do ? Find the answer.
    StreamTransformer<RS, RT> cast<RS, RT>() {
    return StreamTransformer<RS, RT>((Stream<RS> stream, bool b) {
    // What should we do here ?
    });
    }
    }


    main() {

    // ---------------------------------------------------------------------------
    // TEST: unicast controller.
    // ---------------------------------------------------------------------------

    // Create a controller that will be used to inject integers into the "input"
    // stream.
    StreamController<int> controller_unicast = new StreamController<int>();
    // Get the stream "to control".
    Stream<int> integer_stream_unicast = controller_unicast.stream;
    // Apply a transformer on the "input" stream.
    // The method "transform" calls the method "bind", which returns the stream that
    // receives the transformed values.
    Stream<String> string_stream_unicast = integer_stream_unicast.transform(CasterTransformer<int, String>(new Caster()));

    string_stream_unicast.listen((data) {
    print('String => $data');
    });

    // Inject integers into the "input" stream.
    controller_unicast.add(1);
    controller_unicast.add(2);
    controller_unicast.add(3);

    // ---------------------------------------------------------------------------
    // TEST: broadcast controller.
    // ---------------------------------------------------------------------------

    StreamController<int> controller_broadcast = new StreamController<int>.broadcast();
    Stream<int> integer_stream_broadcast = controller_broadcast.stream;
    Stream<String> string_stream_broadcast = integer_stream_broadcast.transform(CasterTransformer<int, String>.broadcast(new Caster()));

    string_stream_broadcast.listen((data) {
    print('Listener 1: String => $data');
    });

    string_stream_broadcast.listen((data) {
    print('Listener 2: String => $data');
    });

    controller_broadcast.add(1);
    controller_broadcast.add(2);
    controller_broadcast.add(3);
    }


    The class CasterTransformer<S, T> extends the abstract class StreamTransformer<S, T>.



    Thus, it implements the method StreamTransformer<RS, RT> cast<RS, RT>().



    On the documentation, it is said that :




    The resulting transformer will check at run-time that all data events of the stream it transforms are actually instances of S, and it will check that all data events produced by this transformer are actually instances of RT.




    See: https://api.dartlang.org/stable/2.1.0/dart-async/StreamTransformer/cast.html



    First, I think that there is a typo in this documentation : it should say "...it transforms are actually instances of RS" (instead of S).



    However, this seems obscure to me.




    • Why do we need a stream transformer to check values types ? The purpose of a transformer is to transform, isn't it ? If the purpose of a component is to check, so why don't we call it a checker ?

    • And, also, why would we need to check that the transformer (we implement) produces the required data ? If it doesn't, then we face a bug that should be fixed.


    Can someone explain the purpose of the method Cast() ?










    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I've implemented the stream transformer. Please note that it is only an exercise (in order to learn Dart). This transformer converts integers into strings. I give the code below, and you can also find it on GitHub.



      // Conceptually, a transformer is simply a function from Stream to Stream that
      // is encapsulated into a class.
      //
      // A transformer is made of:
      // - A stream controller. The controller provides the "output" stream that will
      // receive the transformed values.
      // - A "bind()" method. This method is called by the "input" stream "transform"
      // method (inputStream.transform(<the stream transformer>).

      import 'dart:async';

      /// This class defines the implementation of a class that emulates a function
      /// that converts a data with a given type (S) into a data with another type (T).
      abstract class TypeCaster<S, T> {
      T call(S value);
      }

      /// This class emulates a converter from integers to strings.
      class Caster extends TypeCaster<int, String> {
      String call(int value) {
      return "<${value.toString()}>";
      }
      }

      // StreamTransformer<S, T> is an abstract class. The functions listed below must
      // be implemented:
      // - Stream<T> bind(Stream<S> stream)
      // - StreamTransformer<RS, RT> cast<RS, RT>()

      class CasterTransformer<S, T> implements StreamTransformer<S, T> {

      StreamController<T> _controller;
      bool _cancelOnError;
      TypeCaster<S, T> _caster;

      // Original (or input) stream.
      Stream<S> _stream;

      // The stream subscription returned by the call to the function "listen", of
      // the original (input) stream (_stream.listen(...)).
      StreamSubscription<S> _subscription;

      /// Constructor that creates a unicast stream.
      /// [caster] An instance of "type caster".
      CasterTransformer(TypeCaster<S, T> caster, {
      bool sync: false,
      bool cancelOnError: true
      }) {
      _controller = new StreamController<T>(
      onListen: _onListen,
      onCancel: _onCancel,
      onPause: () => _subscription.pause(),
      onResume: () => _subscription.resume(),
      sync: sync
      );
      _cancelOnError = cancelOnError;
      _caster = caster;
      }

      /// Constructor that creates a broadcast stream.
      /// [caster] An instance of "type caster".
      CasterTransformer.broadcast(TypeCaster<S, T> caster, {
      bool sync: false,
      bool cancelOnError: true
      }) {
      _cancelOnError = cancelOnError;
      _controller = new StreamController<T>.broadcast(
      onListen: _onListen,
      onCancel: _onCancel,
      sync: sync
      );
      _caster = caster;
      }

      /// Handler executed whenever a listener subscribes to the controller's stream.
      /// Note: when the transformer is applied to the original stream, through call
      /// to the method "transform", the method "bind()" is called behind the
      /// scenes. The method "bind()" returns the controller stream.
      /// When a listener is applied to the controller stream, then this function
      /// (that is "_onListen()") will be executed. This function will set the
      /// handler ("_onData") that will be executed each time a value appears
      /// in the original stream. This handler takes the incoming value, casts
      /// it, and inject it to the (controller) output stream.
      /// Note: this method is called only once. On the other hand, the method "_onData"
      /// is called as many times as there are values to transform.
      void _onListen() {
      _subscription = _stream.listen(
      _onData,
      onError: _controller.addError,
      onDone: _controller.close,
      cancelOnError: _cancelOnError
      );
      }

      /// Handler executed whenever the subscription to the controller's stream is cancelled.
      void _onCancel() {
      _subscription.cancel();
      _subscription = null;
      }

      /// Handler executed whenever data comes from the original (input) stream.
      /// Please note that the transformation takes place here.
      /// Note: this method is called as many times as there are values to transform.
      void _onData(S data) {
      _controller.add(_caster(data));
      }

      /// This method is called once, when the stream transformer is assigned to the
      /// original (input) stream. It returns the stream provided by the controller.
      /// Note: here, you can see that the process transforms a value of type
      /// S into a value of type T. Thus, it is necessary to provide a function
      /// that performs the conversion from type S to type T.
      /// Note: the returned stream may accept only one, or more than one, listener.
      /// This depends on the method called to instantiate the transformer.
      /// * CasterTransformer() => only one listener.
      /// * CasterTransformer.broadcast() => one or more listener.
      Stream<T> bind(Stream<S> stream) {
      _stream = stream;
      return _controller.stream;
      }

      // TODO: what should this method do ? Find the answer.
      StreamTransformer<RS, RT> cast<RS, RT>() {
      return StreamTransformer<RS, RT>((Stream<RS> stream, bool b) {
      // What should we do here ?
      });
      }
      }


      main() {

      // ---------------------------------------------------------------------------
      // TEST: unicast controller.
      // ---------------------------------------------------------------------------

      // Create a controller that will be used to inject integers into the "input"
      // stream.
      StreamController<int> controller_unicast = new StreamController<int>();
      // Get the stream "to control".
      Stream<int> integer_stream_unicast = controller_unicast.stream;
      // Apply a transformer on the "input" stream.
      // The method "transform" calls the method "bind", which returns the stream that
      // receives the transformed values.
      Stream<String> string_stream_unicast = integer_stream_unicast.transform(CasterTransformer<int, String>(new Caster()));

      string_stream_unicast.listen((data) {
      print('String => $data');
      });

      // Inject integers into the "input" stream.
      controller_unicast.add(1);
      controller_unicast.add(2);
      controller_unicast.add(3);

      // ---------------------------------------------------------------------------
      // TEST: broadcast controller.
      // ---------------------------------------------------------------------------

      StreamController<int> controller_broadcast = new StreamController<int>.broadcast();
      Stream<int> integer_stream_broadcast = controller_broadcast.stream;
      Stream<String> string_stream_broadcast = integer_stream_broadcast.transform(CasterTransformer<int, String>.broadcast(new Caster()));

      string_stream_broadcast.listen((data) {
      print('Listener 1: String => $data');
      });

      string_stream_broadcast.listen((data) {
      print('Listener 2: String => $data');
      });

      controller_broadcast.add(1);
      controller_broadcast.add(2);
      controller_broadcast.add(3);
      }


      The class CasterTransformer<S, T> extends the abstract class StreamTransformer<S, T>.



      Thus, it implements the method StreamTransformer<RS, RT> cast<RS, RT>().



      On the documentation, it is said that :




      The resulting transformer will check at run-time that all data events of the stream it transforms are actually instances of S, and it will check that all data events produced by this transformer are actually instances of RT.




      See: https://api.dartlang.org/stable/2.1.0/dart-async/StreamTransformer/cast.html



      First, I think that there is a typo in this documentation : it should say "...it transforms are actually instances of RS" (instead of S).



      However, this seems obscure to me.




      • Why do we need a stream transformer to check values types ? The purpose of a transformer is to transform, isn't it ? If the purpose of a component is to check, so why don't we call it a checker ?

      • And, also, why would we need to check that the transformer (we implement) produces the required data ? If it doesn't, then we face a bug that should be fixed.


      Can someone explain the purpose of the method Cast() ?










      share|improve this question















      I've implemented the stream transformer. Please note that it is only an exercise (in order to learn Dart). This transformer converts integers into strings. I give the code below, and you can also find it on GitHub.



      // Conceptually, a transformer is simply a function from Stream to Stream that
      // is encapsulated into a class.
      //
      // A transformer is made of:
      // - A stream controller. The controller provides the "output" stream that will
      // receive the transformed values.
      // - A "bind()" method. This method is called by the "input" stream "transform"
      // method (inputStream.transform(<the stream transformer>).

      import 'dart:async';

      /// This class defines the implementation of a class that emulates a function
      /// that converts a data with a given type (S) into a data with another type (T).
      abstract class TypeCaster<S, T> {
      T call(S value);
      }

      /// This class emulates a converter from integers to strings.
      class Caster extends TypeCaster<int, String> {
      String call(int value) {
      return "<${value.toString()}>";
      }
      }

      // StreamTransformer<S, T> is an abstract class. The functions listed below must
      // be implemented:
      // - Stream<T> bind(Stream<S> stream)
      // - StreamTransformer<RS, RT> cast<RS, RT>()

      class CasterTransformer<S, T> implements StreamTransformer<S, T> {

      StreamController<T> _controller;
      bool _cancelOnError;
      TypeCaster<S, T> _caster;

      // Original (or input) stream.
      Stream<S> _stream;

      // The stream subscription returned by the call to the function "listen", of
      // the original (input) stream (_stream.listen(...)).
      StreamSubscription<S> _subscription;

      /// Constructor that creates a unicast stream.
      /// [caster] An instance of "type caster".
      CasterTransformer(TypeCaster<S, T> caster, {
      bool sync: false,
      bool cancelOnError: true
      }) {
      _controller = new StreamController<T>(
      onListen: _onListen,
      onCancel: _onCancel,
      onPause: () => _subscription.pause(),
      onResume: () => _subscription.resume(),
      sync: sync
      );
      _cancelOnError = cancelOnError;
      _caster = caster;
      }

      /// Constructor that creates a broadcast stream.
      /// [caster] An instance of "type caster".
      CasterTransformer.broadcast(TypeCaster<S, T> caster, {
      bool sync: false,
      bool cancelOnError: true
      }) {
      _cancelOnError = cancelOnError;
      _controller = new StreamController<T>.broadcast(
      onListen: _onListen,
      onCancel: _onCancel,
      sync: sync
      );
      _caster = caster;
      }

      /// Handler executed whenever a listener subscribes to the controller's stream.
      /// Note: when the transformer is applied to the original stream, through call
      /// to the method "transform", the method "bind()" is called behind the
      /// scenes. The method "bind()" returns the controller stream.
      /// When a listener is applied to the controller stream, then this function
      /// (that is "_onListen()") will be executed. This function will set the
      /// handler ("_onData") that will be executed each time a value appears
      /// in the original stream. This handler takes the incoming value, casts
      /// it, and inject it to the (controller) output stream.
      /// Note: this method is called only once. On the other hand, the method "_onData"
      /// is called as many times as there are values to transform.
      void _onListen() {
      _subscription = _stream.listen(
      _onData,
      onError: _controller.addError,
      onDone: _controller.close,
      cancelOnError: _cancelOnError
      );
      }

      /// Handler executed whenever the subscription to the controller's stream is cancelled.
      void _onCancel() {
      _subscription.cancel();
      _subscription = null;
      }

      /// Handler executed whenever data comes from the original (input) stream.
      /// Please note that the transformation takes place here.
      /// Note: this method is called as many times as there are values to transform.
      void _onData(S data) {
      _controller.add(_caster(data));
      }

      /// This method is called once, when the stream transformer is assigned to the
      /// original (input) stream. It returns the stream provided by the controller.
      /// Note: here, you can see that the process transforms a value of type
      /// S into a value of type T. Thus, it is necessary to provide a function
      /// that performs the conversion from type S to type T.
      /// Note: the returned stream may accept only one, or more than one, listener.
      /// This depends on the method called to instantiate the transformer.
      /// * CasterTransformer() => only one listener.
      /// * CasterTransformer.broadcast() => one or more listener.
      Stream<T> bind(Stream<S> stream) {
      _stream = stream;
      return _controller.stream;
      }

      // TODO: what should this method do ? Find the answer.
      StreamTransformer<RS, RT> cast<RS, RT>() {
      return StreamTransformer<RS, RT>((Stream<RS> stream, bool b) {
      // What should we do here ?
      });
      }
      }


      main() {

      // ---------------------------------------------------------------------------
      // TEST: unicast controller.
      // ---------------------------------------------------------------------------

      // Create a controller that will be used to inject integers into the "input"
      // stream.
      StreamController<int> controller_unicast = new StreamController<int>();
      // Get the stream "to control".
      Stream<int> integer_stream_unicast = controller_unicast.stream;
      // Apply a transformer on the "input" stream.
      // The method "transform" calls the method "bind", which returns the stream that
      // receives the transformed values.
      Stream<String> string_stream_unicast = integer_stream_unicast.transform(CasterTransformer<int, String>(new Caster()));

      string_stream_unicast.listen((data) {
      print('String => $data');
      });

      // Inject integers into the "input" stream.
      controller_unicast.add(1);
      controller_unicast.add(2);
      controller_unicast.add(3);

      // ---------------------------------------------------------------------------
      // TEST: broadcast controller.
      // ---------------------------------------------------------------------------

      StreamController<int> controller_broadcast = new StreamController<int>.broadcast();
      Stream<int> integer_stream_broadcast = controller_broadcast.stream;
      Stream<String> string_stream_broadcast = integer_stream_broadcast.transform(CasterTransformer<int, String>.broadcast(new Caster()));

      string_stream_broadcast.listen((data) {
      print('Listener 1: String => $data');
      });

      string_stream_broadcast.listen((data) {
      print('Listener 2: String => $data');
      });

      controller_broadcast.add(1);
      controller_broadcast.add(2);
      controller_broadcast.add(3);
      }


      The class CasterTransformer<S, T> extends the abstract class StreamTransformer<S, T>.



      Thus, it implements the method StreamTransformer<RS, RT> cast<RS, RT>().



      On the documentation, it is said that :




      The resulting transformer will check at run-time that all data events of the stream it transforms are actually instances of S, and it will check that all data events produced by this transformer are actually instances of RT.




      See: https://api.dartlang.org/stable/2.1.0/dart-async/StreamTransformer/cast.html



      First, I think that there is a typo in this documentation : it should say "...it transforms are actually instances of RS" (instead of S).



      However, this seems obscure to me.




      • Why do we need a stream transformer to check values types ? The purpose of a transformer is to transform, isn't it ? If the purpose of a component is to check, so why don't we call it a checker ?

      • And, also, why would we need to check that the transformer (we implement) produces the required data ? If it doesn't, then we face a bug that should be fixed.


      Can someone explain the purpose of the method Cast() ?







      stream dart






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 2 days ago

























      asked 2 days ago









      Denis Beurive

      94




      94
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          3
          down vote













          The cast method is there to help typing the operation.



          If you have a StreamTransformer<num, int>, it transforms numbers to integers (say, by calling .toInt() on them and then adding 42, because that is obviously useful!).
          If you want to use that transformer in some place that expects a StreamTransformer<int, num>, then you can't. Since num is not a sub-type of int, the transformer is not assignable to that type.



          But you know, because you understand how a stream transformer actually works, that the first type argument is only used for inputs. Something that accepts any num should safely be useable where it's only given ints.
          So, to convince the type system that you know what you are doing, you write:



          StreamTransformer<int, num> transform = myTranformer.cast<int, num>();


          Now, the tranformer takes any integer (RS), checks that it's a num (S), passes it to myTransformer which calls toInt() and adds 42, then the resulting int (T) is passed back and transformer checks that it is a num (RT) and emits that.



          Everything works and the type system is happy.



          You can use cast to do things that will never work at run-time, because all it does is to add extra run-time checks that convinces the static type system that things will either succeed or throw at those checks.



          The easiest way to get an implementation of StreamTransformer.cast is to use th e StreamTransformer.castFrom static method:



          StreamTransformer<RS, RT> cast<RS, RT>() => StreamTransformer.castFrom(this);


          That will use the system's default cast wrapper on your own transformer.






          share|improve this answer























          • Thank you for your response. I understand that the method just instantiate a new transformer which is compatible with the required input/output data types. I updated my example to illustrate this point.
            – Denis Beurive
            yesterday










          • Ah, yes. Added note on how to create a new wrapped transformer.
            – lrn
            yesterday










          • Thank you for the note. Indeed, castFrom(this) is handy.
            – Denis Beurive
            yesterday











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53372895%2fdart-what-does-streamtransformerrs-rt-castrs-rt-do%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          3
          down vote













          The cast method is there to help typing the operation.



          If you have a StreamTransformer<num, int>, it transforms numbers to integers (say, by calling .toInt() on them and then adding 42, because that is obviously useful!).
          If you want to use that transformer in some place that expects a StreamTransformer<int, num>, then you can't. Since num is not a sub-type of int, the transformer is not assignable to that type.



          But you know, because you understand how a stream transformer actually works, that the first type argument is only used for inputs. Something that accepts any num should safely be useable where it's only given ints.
          So, to convince the type system that you know what you are doing, you write:



          StreamTransformer<int, num> transform = myTranformer.cast<int, num>();


          Now, the tranformer takes any integer (RS), checks that it's a num (S), passes it to myTransformer which calls toInt() and adds 42, then the resulting int (T) is passed back and transformer checks that it is a num (RT) and emits that.



          Everything works and the type system is happy.



          You can use cast to do things that will never work at run-time, because all it does is to add extra run-time checks that convinces the static type system that things will either succeed or throw at those checks.



          The easiest way to get an implementation of StreamTransformer.cast is to use th e StreamTransformer.castFrom static method:



          StreamTransformer<RS, RT> cast<RS, RT>() => StreamTransformer.castFrom(this);


          That will use the system's default cast wrapper on your own transformer.






          share|improve this answer























          • Thank you for your response. I understand that the method just instantiate a new transformer which is compatible with the required input/output data types. I updated my example to illustrate this point.
            – Denis Beurive
            yesterday










          • Ah, yes. Added note on how to create a new wrapped transformer.
            – lrn
            yesterday










          • Thank you for the note. Indeed, castFrom(this) is handy.
            – Denis Beurive
            yesterday















          up vote
          3
          down vote













          The cast method is there to help typing the operation.



          If you have a StreamTransformer<num, int>, it transforms numbers to integers (say, by calling .toInt() on them and then adding 42, because that is obviously useful!).
          If you want to use that transformer in some place that expects a StreamTransformer<int, num>, then you can't. Since num is not a sub-type of int, the transformer is not assignable to that type.



          But you know, because you understand how a stream transformer actually works, that the first type argument is only used for inputs. Something that accepts any num should safely be useable where it's only given ints.
          So, to convince the type system that you know what you are doing, you write:



          StreamTransformer<int, num> transform = myTranformer.cast<int, num>();


          Now, the tranformer takes any integer (RS), checks that it's a num (S), passes it to myTransformer which calls toInt() and adds 42, then the resulting int (T) is passed back and transformer checks that it is a num (RT) and emits that.



          Everything works and the type system is happy.



          You can use cast to do things that will never work at run-time, because all it does is to add extra run-time checks that convinces the static type system that things will either succeed or throw at those checks.



          The easiest way to get an implementation of StreamTransformer.cast is to use th e StreamTransformer.castFrom static method:



          StreamTransformer<RS, RT> cast<RS, RT>() => StreamTransformer.castFrom(this);


          That will use the system's default cast wrapper on your own transformer.






          share|improve this answer























          • Thank you for your response. I understand that the method just instantiate a new transformer which is compatible with the required input/output data types. I updated my example to illustrate this point.
            – Denis Beurive
            yesterday










          • Ah, yes. Added note on how to create a new wrapped transformer.
            – lrn
            yesterday










          • Thank you for the note. Indeed, castFrom(this) is handy.
            – Denis Beurive
            yesterday













          up vote
          3
          down vote










          up vote
          3
          down vote









          The cast method is there to help typing the operation.



          If you have a StreamTransformer<num, int>, it transforms numbers to integers (say, by calling .toInt() on them and then adding 42, because that is obviously useful!).
          If you want to use that transformer in some place that expects a StreamTransformer<int, num>, then you can't. Since num is not a sub-type of int, the transformer is not assignable to that type.



          But you know, because you understand how a stream transformer actually works, that the first type argument is only used for inputs. Something that accepts any num should safely be useable where it's only given ints.
          So, to convince the type system that you know what you are doing, you write:



          StreamTransformer<int, num> transform = myTranformer.cast<int, num>();


          Now, the tranformer takes any integer (RS), checks that it's a num (S), passes it to myTransformer which calls toInt() and adds 42, then the resulting int (T) is passed back and transformer checks that it is a num (RT) and emits that.



          Everything works and the type system is happy.



          You can use cast to do things that will never work at run-time, because all it does is to add extra run-time checks that convinces the static type system that things will either succeed or throw at those checks.



          The easiest way to get an implementation of StreamTransformer.cast is to use th e StreamTransformer.castFrom static method:



          StreamTransformer<RS, RT> cast<RS, RT>() => StreamTransformer.castFrom(this);


          That will use the system's default cast wrapper on your own transformer.






          share|improve this answer














          The cast method is there to help typing the operation.



          If you have a StreamTransformer<num, int>, it transforms numbers to integers (say, by calling .toInt() on them and then adding 42, because that is obviously useful!).
          If you want to use that transformer in some place that expects a StreamTransformer<int, num>, then you can't. Since num is not a sub-type of int, the transformer is not assignable to that type.



          But you know, because you understand how a stream transformer actually works, that the first type argument is only used for inputs. Something that accepts any num should safely be useable where it's only given ints.
          So, to convince the type system that you know what you are doing, you write:



          StreamTransformer<int, num> transform = myTranformer.cast<int, num>();


          Now, the tranformer takes any integer (RS), checks that it's a num (S), passes it to myTransformer which calls toInt() and adds 42, then the resulting int (T) is passed back and transformer checks that it is a num (RT) and emits that.



          Everything works and the type system is happy.



          You can use cast to do things that will never work at run-time, because all it does is to add extra run-time checks that convinces the static type system that things will either succeed or throw at those checks.



          The easiest way to get an implementation of StreamTransformer.cast is to use th e StreamTransformer.castFrom static method:



          StreamTransformer<RS, RT> cast<RS, RT>() => StreamTransformer.castFrom(this);


          That will use the system's default cast wrapper on your own transformer.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited yesterday

























          answered yesterday









          lrn

          9,3141217




          9,3141217












          • Thank you for your response. I understand that the method just instantiate a new transformer which is compatible with the required input/output data types. I updated my example to illustrate this point.
            – Denis Beurive
            yesterday










          • Ah, yes. Added note on how to create a new wrapped transformer.
            – lrn
            yesterday










          • Thank you for the note. Indeed, castFrom(this) is handy.
            – Denis Beurive
            yesterday


















          • Thank you for your response. I understand that the method just instantiate a new transformer which is compatible with the required input/output data types. I updated my example to illustrate this point.
            – Denis Beurive
            yesterday










          • Ah, yes. Added note on how to create a new wrapped transformer.
            – lrn
            yesterday










          • Thank you for the note. Indeed, castFrom(this) is handy.
            – Denis Beurive
            yesterday
















          Thank you for your response. I understand that the method just instantiate a new transformer which is compatible with the required input/output data types. I updated my example to illustrate this point.
          – Denis Beurive
          yesterday




          Thank you for your response. I understand that the method just instantiate a new transformer which is compatible with the required input/output data types. I updated my example to illustrate this point.
          – Denis Beurive
          yesterday












          Ah, yes. Added note on how to create a new wrapped transformer.
          – lrn
          yesterday




          Ah, yes. Added note on how to create a new wrapped transformer.
          – lrn
          yesterday












          Thank you for the note. Indeed, castFrom(this) is handy.
          – Denis Beurive
          yesterday




          Thank you for the note. Indeed, castFrom(this) is handy.
          – Denis Beurive
          yesterday


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53372895%2fdart-what-does-streamtransformerrs-rt-castrs-rt-do%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

          Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

          A Topological Invariant for $pi_3(U(n))$