Boost logo

Boost :

From: Braddock Gaskill (braddock_at_[hidden])
Date: 2007-02-25 07:03:42


I've recently been working on a system making use of complex pipelines
of loaders and events, and was looking at some similar "signal flow"
concepts.

A few comments:

1) This "signal flow" library sounds very similar to the "pipes and
filters" pattern. If the name invokes that relationship, it might get
more use (if it is up to the semantics of pipes and filters).

2) Using functions or functors directly would avoid the need for any
signal_link glue in many cases. The output signal type could be
derived from the return type of the function.

/** Function which upon receiving an image signal, outputs the horizontally
flipped image **/
Image flipImage(Image inputImage);

/** Functor which performs some analysis **/
struct AnalyzeImage {
  Vector operator()(Image inputImage);
};

...later...
boost::function<Image (Image)> flipper = flipImage;
boost::function<Vector (Image)> analysis = AnalyzeImage();

// perform the whole video analysis and display the results
frame_rate >>= video_generator >>= differencer >>= flipper >>=
 analysis >>= database >>= display1;

I added the intermediate function object, because I know you can get
the result type and signature from it...perhaps you can be clever and
avoid it in most cases. Or at least provide an in-line glue syntax like:

signal_func<Image (Image)>(f)

This has the benefit that I need no signal_link glue objects, nor does
my functional code require any knowledge of signals, slots, or
signal_links.

3) Rationale? Your example usage seems to be almost equivalent to:

void imagePipeline() {
  Image img = video_generator();
  img = differencer(img);
  img = flipper(img);
  Vector vec = analysis(img);
  database(vec);
  display1(img);
}

Obviously this code is more readable by any C++ programmer and has no
boost dependencies, and could even be called by a signal. So exactly
what is the rationale for signal_flow?

The rationale could be the ability to dynamically reconfigure
pipelines at runtime. But your example doesn't seem to provide a way
to do this (no "flow traversal" or visitor iteration).

The rationale could be to dynamically build pipelines at runtime. But
your syntax is primarily for multiple stages at compile-time, and if
you start building your pipeline one at a time you can just use
signal.connect() calls.

The rationale could be to provide parallelism to a data flow. But
boost::signals doesn't have (yet) the functionality to provide this.

There is something here, but it is hard to put my finger on it...

Braddock Gaskill
Dockside Vision Inc


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk