alternative to "hot" inputs

385 views
Skip to first unread message

Forrest Oliphant

unread,
Jun 15, 2012, 5:04:54 PM6/15/12
to flow-based-...@googlegroups.com
Here is my latest Meemoo creation: http://meemoo.org/iframework/#example/rainbowclock

I have run across a funny issue in coding more complex images like this. In most of the modules, I want every input to potentially trigger a calculation (and output). But if several inputs change at the same time, I don't want to .

My solution was to put a 1000/30 ms timeout on every input. If more inputs are hit in that short timespan, the timeout is cleared. Example with the string-join.html module: https://github.com/forresto/meemoo-modules/blob/gh-pages/string-join.html#L36

This isn't optimal, because each module is now slowing down the data-flow. You can also see that in 14:transform, the image is rendered twice per second anyway, as the rotate input is hit before the image from 5:text makes it (because 7:string-join and 5:text modules have the timeout as well).

Pure Data uses "hot" inputs. I could do something like this that would only send the data when a "send" input is hit, but that would make for more complicated graphs.

Is there a better or standard data-flow way to solve this?

- Forrest

Dan

unread,
Jun 17, 2012, 10:17:48 AM6/17/12
to flow-based-...@googlegroups.com
If I have understood your problem well then my comments could be useful and I think this is a general issue.
This is a classical problem of race condition as in electronics (http://en.wikipedia.org/wiki/Race_condition). Please be aware that this kind of issue is more similar to the race condition as in electronics and not in computing (http://en.wikipedia.org/wiki/Race_condition#Computing). Even if the problem is the same (i.e. race condition), in computing it is perceived as specific to imperative languages that do operations upon shared states. FBP is really similar to electronics. The difference is control flow (imperative programming) versus data flow (declarative programming like FBP).

In electronics a way to solve this kind of problem is to create the final circuit using Karnaugh maps (http://en.wikipedia.org/wiki/Karnaugh_map). Our software program case is not suitable for a similar solution (i.e. the hardware is boolean at its lowest level but the software is a higher more functional level).

I have proposed a possible solution into another post of mine regarding types of connections (see: https://groups.google.com/d/msg/flow-based-programming/JkInzGvySAg/EH1d2rQceo8J and the other post related). Even if at first glance it does not address your problem in fact it was exactly the problem I have started with in mind. It seems the depth of the consequences of what I have said in that post was not clearly understood. Please read first that post and come back here.

I want to translate the topic of that post to your problem. In any network (FBP in our case) there is a "wave of change" (wave of data triggering changes) expressed as IPs (events, messages) that travel through the network. Timing is an issue and we want to avoid it nevertheless we have to take it into account. Time is order.

In your case the network is dealing with discreet events (e.g. seconds ticks) that propagate and generate other events (i.e. IPs generated). The problem shows up when these events converge to a processor (same FBP node). The main questions are:
  1. When exactly to start the evaluation of a process (or subprocess)?
  2. Did all the "necessary" IPs (events, messages) arrived?
  3. Are the IPs in sync?
  4. Are they related to the same "logic" wave?
Normally the logic of your program that is the data flow network itself should not include all this problematics that is an "implementation detail" of the underlying system but when the time is part of the logic then the time is part of your data.

In that post of mine I have proposed "material" (discreet) connections and "potential" (continuous) connections. Whenever the logic says that the outputs of a component are continuously changing as its inputs are changing then you connect all the subcomponents that contribute to that process with "potential" connections (like in hardware with electrical wires).
Of course the compiled software program will not act continuously but the sampling will be given by all the events (IPs) that are traveling through the (other) "material" connections. The catch is: all the potential connections are evaluated opposite as materials ones i.e. pull data versus push data. "Pull" case is similar to the classical imperative and functional languages were the parameters of a function are pulled from the environment exactly when the function is called (control flow) as opposed to the reactive programming where evaluation is triggered when the data arrives (data flow).

All that said, it means that the final block (node: "combine") should update the input data only when some sampling event (i.e. like a clock in electronics) is arriving through a "material" connection. This kind of differentiation between what I have called "material" and "potential" connections helps a lot in implementing lazy programming too i.e. not evaluating some nodes (subnetworks) until it will be really necessary the case (i.e. somewhere in the downstream there is a "pull" request). Also this is useful to implement "if...then..else" or other conditionals without evaluating all the paths.

Unfortunately this kind of "solution" is system related (FBP compiler, runtime system or interpreter). If you don't have it then you can not use this kind of features when you try to implement your network of components.

Instead of trying to have a long post here it would be nice to read the other materials referred in that post (for instance "flowlang" group of discussions).

In the end I am curious if my comments are related to your issue or I was just rambling around :).

Regards,
Dan

Forrest Oliphant

unread,
Jun 27, 2012, 11:56:54 AM6/27/12
to flow-based-...@googlegroups.com
Good ramblings, and related. I am trying to make this framework as easy as possible for non-coders, and this issue is tough to work around.

I realized that the timeout method isn't good; changes can happen faster than 1000/30, and then it doesn't do anything.

Still thinking about [transform] and [combine] in http://meemoo.org/iframework/#example/rainbowclock ...

- Forrest

Brad Cox

unread,
Jul 20, 2012, 11:07:46 AM7/20/12
to flow-based-...@googlegroups.com
FYI Gremlin Pipes ( https://github.com/tinkerpop/pipes/wiki/ ) uses what sounds like the approach you describe. They call it lazy evaluation.

On Fri, Jul 20, 2012 at 9:51 AM, Patrick Down <patric...@gmail.com> wrote:

Here's a newbe perspective from a programmer who has not thought about FPB in a while.  

It seems that there is an implicit flow on information back through the network.  Let's say final node want's to update it's display X times a second.  After composing and displaying the image it signals that it can accept new inputs.  This flows back through the network to the producer nodes at the beginning of the network. These guy's produce fresh data the flows forward through the network.  That way no one is actually doing any computation until it is needed.  



--
Cell: 703-594-1883
Blog: http://bradjcox.blogspot.com
Web: http://virtualschool.edu
Manassas VA 20111

Dan

unread,
Jul 20, 2012, 11:11:49 AM7/20/12
to flow-based-...@googlegroups.com
Patrick, I like your example.

Patrick Down said: "This flows back through the network to the producer nodes at the beginning of the network. These guy's produce fresh data the flows forward through the network.  That way no one is actually doing any computation until it is needed."

In terms of FBP, the solution I have found for this it was described in another post of mine: https://groups.google.com/d/msg/flow-based-programming/JkInzGvySAg/EH1d2rQceo8J
Please have a look before reading further.

The mechanism of what I have described as "potential" connections is exactly this: the processes (i.e. components evaluations) are triggered from downstream toward upstream as needed (conventionally from right to left). Remember that the flow (data flow) is from left to right, only triggering in this case is from right to left (i.e. control flow). In this case the control flow tells how much data will be produced.
 
The IPs flows logically from left to right (it is just a drawing convention in order to understand better). In fact it is so similar to how the actual imperative languages are doing the evaluation of the functions (in the parameter place is a function call that has a parameter that is a function call  and so on). Example:
in->A -> B -> C->out; //FBP
out = C(B(A(in)));       // classic imperative
The example above is simple. Imagine you have branches and "diamond shape" networks that we have discussed about some time ago.
The bottom line is: we are discussing about "PUSH" vs. "PULL" but this is not just an implementation techniques; it is affecting the logic and the behavior.

Maybe that post deserves a second look from this perspective.

Regards,
Dan

Dan

unread,
Jul 20, 2012, 11:19:14 AM7/20/12
to flow-based-...@googlegroups.com
Brad:  "They call it lazy evaluation."

Yes, it is exactly lazy evaluation. Execute as needed.
In the case I have described, the "potential" connections are "executed" (i.e. pull the IPs as oppose to push) only when they are triggered somewhere in the downstream, i.e. when an IP that flows through a parallel (other path) "material" connection will trigger the evaluation of a network of "potentially" interconnected components in the upstream.

Regards,
Dan

Paul Morrison

unread,
Jul 21, 2012, 9:49:09 AM7/21/12
to flow-based-...@googlegroups.com
Hi Forrest, I just want to make sure I understand your problem.  I assume you have a process receiving inputs (IPs) at multiple input ports. If 2 or more inputs arrive at different input ports at the same time (?), you want to process - just one, or neither?  Also, is it only when they arrive at exactly the same time, or within some specified time interval?

I suspect the latter because you talk about 1000/30 ms... but I am afraid I don't know what that means.  Do you mean 33.333 ms?!  Or does the slash mean something different?  Once I get your answers, I can do some thinking about your problem. :-)

Forrest Oliphant

unread,
Jul 21, 2012, 12:25:29 PM7/21/12
to flow-based-...@googlegroups.com
There are multiple inputs [background, image, scale, translate, rotate] that affect one output [image]. Changing any of them should change the output.

I ended up relying on the new requestAnimationFrame browser function. This is a loop that runs at 60htz (or tries), but only if the browser window is visible. All hot inputs set a flag to render on the next requestAnimationFrame call.

Here it is in action, drawing a square with recursive feedback: http://meemoo.org/iframework/#gist/3124854 (I'm getting 20fps.)

If you switch to a new tab and back, you'll see the jump as it starts rendering again.

So, I just went with the "hot" input method, but with requestAnimationFrame it won't try to do more redraws than the refresh rate of the screen. There are still race condition issues, but I'm just ignoring them for now. The solutions seem too complicated for my goal of prioritizing simplicity in the UX.

- Forrest

Paul Morrison

unread,
Jul 21, 2012, 3:08:04 PM7/21/12
to flow-based-...@googlegroups.com
I am not sure I got an answer to my question, but I gather that you have a picture that is being  refreshed at 60htz, which I assume works out to 16.67 ms per refresh - I think we can do it with FBP, without having to add any new function to the scheduler... if I have understood correctly what you are trying to do.

The first thing is that, in FBP, you don't want to be waiting on two or more input ports, as you could be waiting on one input port while IPs pile up at another - this is a recipe for a deadlock.  Your published solution I believe requires a non-supendable receive, which is not supported in any of the FBP implementations I've worked on --- nor needed IMO.

So first I would suggest you bring all of a process's inputs into a single input port, appropriately tagged so you can tell what they are.   IPs arriving at a single input port fed by multiple output ports are handled on a first-come, first-served basis, so you don't risk deadlock. 

Now, if I understand your application correctly, you want to make sure the diagram is updated at 60htz (or less), but you are worried that too many inputs may cause you to miss a clock tick.   A somewhat similar problem is described in Chap. 19 of the 2nd edition, in the context of checkpointing.  It's Chap. 20 in the first edition - http://www.jpaulmorrison.com/fbp/checkpt.shtml .

So, I am suggesting that you feed a series of timer IPs (generated by a separate timer process) into the same input port, giving you an input stream looking like Diagram 20.8 in the 1st edition of my book, or Diagram 19.6 in the 2nd edition.   You don't have to drive the display using the clock ticks, although you could if the non-timer data IPs are relatively infrequent compared to the clock ticks, but I think you could just as well check the time after each IP is received and do the display if the time interval (16.67 ms) has expired.  Injecting the clock tick IPs into the merged stream should ensure that you don't miss a refresh because you are waiting for some other kind of data.

What do you - or anyone else who is interested - think?!

Sam Watkins

unread,
Jul 22, 2012, 7:42:00 AM7/22/12
to flow-based-...@googlegroups.com
hi Forrest,

In your example, the clock feeds into string-join (to make the text like
12:34:56) and color-hsla (to make the color). You then combine this
text and color in the text component, producing a rendered image of that
text in that color.

As I understand, your 'text' component might render the image twice,
because both inputs receive a signal at slightly different times.
But you want it to render only once, since they both came from the same
clock tick signal originally.

So, the evaluator should be configured to do as much work 'upstream' as
much as it can, before it updates a 'downstream' component having several
inputs.

Processing can continue to the downstream component if:

1. all inputs have been signalled, or
2. no further processing can be done upstream at that time

How best to implement that, I'm not exactly sure.

You're working with a different sort of network, compared to regular
FBP. It seems closer to a functional / relational / constraint logic
sort of network.

It's a nice example program, anyway!


Sam

David Barbour

unread,
Jul 28, 2012, 11:57:39 AM7/28/12
to flow-based-...@googlegroups.com
Hello Forrest,

A simple, effective solution is to add a "touch" event to each dataflow. When you know an update is coming soon, you send a touch event. Touches propagate through the network independently of the primary data updates. 

For linear dataflows, the touches are a simple propagation (see a touch? send a touch). For dataflows that receive updates from multiple sources, e.g.  A & B -> C: we send a touch on C the first time we see a touch on A or B. If B is touched, and we receive an update on A (or vice versa), we wait to propagate. For dataflows that send updates to multiple sources, e.g. A -> B & C, we might touch to both B&C after receiving touch on A. 

We might also introduce a "cancel" message to account for those cases when we've touched but decide (due to filtering or splitting) that we don't need to update a given task. The important bit is that we always send an update at some point after sending a touch. The idea can be modified easily with features like counting, indicating how many updates are coming, etc.

Managing these touches has an overhead proportional to the size of the network (though you can introduce barriers or model partitions across which touches are dropped). But the costs are small, predictable - and the win can be enormous, eliminating worst-case exponential costs in networks that merge many data sources.

Regards,

David Barbour
--
bringing s-words to a pen fight

Paul Morrison

unread,
Jul 28, 2012, 2:23:54 PM7/28/12
to flow-based-...@googlegroups.com
Interesting idea, David.  However, in the FBP context, I think you are either introducing a second network of essentially zero-capacity connections, or you are sacrificing configurability (if A and B both "know about" C, without going through the network).  JavaFBP does have a component priority facility, which might be worth trying out.  People have suggested adding a priority attribute to the IPs (queue-jumpers), but IMO that makes the application as a whole less reliable.

Either way, IMO it is much simpler to do what I suggested earlier - did you try it, Forrest? -  which is to feed multiple output ports into a single input port.  If you want really fast response, you can use a connection of capacity 1.  If you want better than that, I suspect you are going to have to build your own scheduler!  

David Barbour

unread,
Jul 28, 2012, 3:14:42 PM7/28/12
to flow-based-...@googlegroups.com
On Sat, Jul 28, 2012 at 11:23 AM, Paul Morrison <paul.m...@rogers.com> wrote:
Interesting idea, David.  However, in the FBP context, I think you are either introducing a second network of essentially zero-capacity connections, or you are sacrificing configurability (if A and B both "know about" C, without going through the network).  JavaFBP does have a component priority facility, which might be worth trying out.  People have suggested adding a priority attribute to the IPs (queue-jumpers), but IMO that makes the application as a whole less reliable.

Excuse my notation. (A&B -> C) indicates a process that receives IPs on ports labeled A and B, and pushes IPs on a port labeled C. The logic, the FBP process, is hidden in the arrow.  The arrow is a self-enclosed entity; it doesn't know anything about the context in which it is used. 

I am not suggesting a second network, nor am I sacrificing configurability. Indeed, my suggestion can be directly modeled in FBP. However, some IPs would serve as `control`, e.g. for touch or cancel-touch.
 

Either way, IMO it is much simpler to do what I suggested earlier - did you try it, Forrest? -  which is to feed multiple output ports into a single input port.  If you want really fast response, you can use a connection of capacity 1.  If you want better than that, I suspect you are going to have to build your own scheduler!  

I believe you misunderstood the problem Forrest is attempting to solve. You earlier wrote:

I assume you have a process receiving inputs (IPs) at multiple input ports. If 2 or more inputs arrive at different input ports at the same time (?), you want to process - just one, or neither?  

Forrest wants to process both inputs, but wants to process them together (rather than one at a time). E.g. if the time on the clock and the color of the clock change at approximately the same time, we would want to send only one "Render" IP that addresses change in both color and clock, as opposed to sending two "Render" IPs in short succession. 

Forrest's current solution is a makeshift hack: he uses timeouts to estimate when IPs arrive at "the same time". This has the seriously unfortunate consequence of increasing system latency at each step ("each module is now slowing down the data-flow"). OTOH, the other choice of sending an IP whenever we receive an IP  to send updates

I'm from the reactive (FRP, synchronous reactive, etc.) community, never have developed FBP. But Forrest is essentially modeling a reactive system in FBP, and the problem he describes is a familiar one. (See a related discussion at LtU: http://lambda-the-ultimate.org/node/4453#comment-69657). While Forrest's ad-hoc clocked approach is semantically dubious and drastically increases latency, it does avoid costs that are potentially exponential in the size of the network. 

The `touch` approach I described adds no latency, and allows us to stick with composition of opaque processes. Whereas other traditional solutions (such as topological sorts) could avoid the overheads of control messages, but would require a more whitebox compilation. 

Regards,

David Barbour
 

On Saturday, July 28, 2012 11:57:39 AM UTC-4, dmbarbour wrote:
Hello Forrest,

A simple, effective solution is to add a "touch" event to each dataflow. When you know an update is coming soon, you send a touch event. Touches propagate through the network independently of the primary data updates. 

For linear dataflows, the touches are a simple propagation (see a touch? send a touch). For dataflows that receive updates from multiple sources, e.g.  A & B -> C: we send a touch on C the first time we see a touch on A or B. If B is touched, and we receive an update on A (or vice versa), we wait to propagate. For dataflows that send updates to multiple sources, e.g. A -> B & C, we might touch to both B&C after receiving touch on A. 

We might also introduce a "cancel" message to account for those cases when we've touched but decide (due to filtering or splitting) that we don't need to update a given task. The important bit is that we always send an update at some point after sending a touch. The idea can be modified easily with features like counting, indicating how many updates are coming, etc.

Managing these touches has an overhead proportional to the size of the network (though you can introduce barriers or model partitions across which touches are dropped). But the costs are small, predictable - and the win can be enormous, eliminating worst-case exponential costs in networks that merge many data sources.

Regards,

David Barbour


Paul Morrison

unread,
Jul 28, 2012, 5:18:22 PM7/28/12
to flow-based-...@googlegroups.com
On 28/07/2012 3:14 PM, David Barbour wrote:
I believe you misunderstood the problem Forrest is attempting to solve. You earlier wrote:

I assume you have a process receiving inputs (IPs) at multiple input ports. If 2 or more inputs arrive at different input ports at the same time (?), you want to process - just one, or neither?  

Forrest wants to process both inputs, but wants to process them together (rather than one at a time). E.g. if the time on the clock and the color of the clock change at approximately the same time, we would want to send only one "Render" IP that addresses change in both color and clock, as opposed to sending two "Render" IPs in short succession. 
You're right - I did misunderstand!  OK, so how about taking the same approach that I suggested, with multiple streams feeding into one input port, plus a stream of clock ticks feeding into it as well... but just output one "consolidated" IP  for clock ticks preceded by non-clock tick IPs.

If you don't like this, perhaps you could post some code for the touch solution - I'm afraid I am having trouble visualizing it... :-)

David Barbour

unread,
Jul 28, 2012, 7:38:25 PM7/28/12
to flow-based-...@googlegroups.com
Your approach to clocking may be cleaner than Forrest's, but still introduces considerable latency. E.g. if we chained 100 FBP processes in a row, and each was pushing only on clock signals at 30Hz, we'd expect 3.33 seconds to see a change on one end reach the other. There is, of course, always some latency involved in such chains, but avoiding a clocked logic could cut the latency down to milliseconds even for 100 processes.

The touch solution is simple enough, and does not limit latency. If I were modeling it in procedural it might look like:

process(iport A, iport B, oport C) {
  var a_touched = false
  var a_value = ""
  var b_touched = false
  var b_value = ""
  while(true) {
      var started_with_touch = (a_touched || b_touched);
      wait([A,B]) // returns when data is available
      while(!empty(A)) {
          var v = take(A)
          if(v == "touch") {
             a_touched = true
          } else {
             a_touched = false
             a_value = v
          }
      }
      while(!empty(B)) {
          var v = take(B)
          if(v == "touch") {
             b_touched = true
          } else {
             b_touched = false
             b_value = v
          }
      }
      var ended_with_touch = (a_touched || b_touched);
      if (ended_with_touch && !started_with_touch)
          put(C, "touch")
     else if(!ended_with_touch)
          put(C, foo(a_value,b_value))
  }
}

Obviously, a lot here could be cleaned up, abstracted, made more declarative, etc. And this only describes what happens in one specific process (of type A&B->C), as opposed to the network effects. There is no obvious change on the FBP network for including touches; it'd be a discipline that each process supports, which makes it a good candidate for adding to port communication protocols in general.

What happens at the network level, then, is that these touch values propagate through the network ahead of the changes (usually not very far ahead), and they can stall certain processes. Where touch is most profitable is when one source results in multiple outputs (C->D&E) that may be processed in parallel before zipping back together down the line.

Regards,

Dave


Dan

unread,
Jul 29, 2012, 7:58:45 AM7/29/12
to flow-based-...@googlegroups.com
Hi Paul,

Paul: "So first I would suggest you bring all of a process's inputs into a single input port, appropriately tagged so you can tell what they are.  IPs arriving at a single input port fed by multiple output ports are handled on a first-come, first-served basis, so you don't risk deadlock.

First of all one port has one single role. If we need to pile different IPs with different types and roles and push them into a single port it means we have a "technical issue". For me it does not make any sense.

The main problem here is that we want to compute the final result (a rendered image in our case) at a pace dictated by a clock tick. The rhythm of the incoming IPs used to compute the image is different than the clock tick used to render that image. The inability to deal with this difference in "data cadence" creates the problem in the first place. That's why I have described in my previous post that the IPs should be pulled only when needed (and latched) instead of pushed. Yes, some of the (input) IPs might be thrown away in the process. This remark is related to what a good FBP solution we can provide and not to practical aspects which Forrest need to implement in the particular framework he is using.

Regards,
Dan

Sam Watkins

unread,
Jul 29, 2012, 9:06:51 AM7/29/12
to flow-based-...@googlegroups.com
hi guys,

If you have some simple math like

x = 4 (input)
y = x + 1
z = x * 2
a = y / z (output)

the answer a = 5/8 = 0.625

if we than set x = 5, as a different input,

we want to recalculate a only once, the new value of a is 6/10 = 0.6
we don't want to recalculate a twice because it has two inputs that
both changed. they both changed together, from a single cause, so we
recalculate y only once.

the original problem with drawing a clock is similar to this. When the
input (clock time) changes, we want to recalculate everything else in
the network exactly once, in order. It's not really a general FBP
problem, more relational logic, since one change in the input should
change everything else exactly once.

/me out

Forrest Oliphant

unread,
Jul 30, 2012, 6:22:51 AM7/30/12
to flow-based-...@googlegroups.com
I stumbled upon this FBP group not really understanding the distinction between FBP, reactive, and other paradigms... I know enough to be dangerous, but I'm learning.

I am trying to understand the touch concept and pseudocode. In the clock example, what sends the touch and how does it flow through the graph?

Also, thinking about clocks, it would make sense to process the image for the next second. Then in the output you should show the processed image much closer to the actual second tick.

Now that I am playing with intentional feedback loops, the requestAnimationFrame timeout method works really well: http://meemoo.org/iframework/#gist/3124854

- Forrest

David Barbour

unread,
Jul 30, 2012, 11:27:25 AM7/30/12
to flow-based-...@googlegroups.com
On Mon, Jul 30, 2012 at 3:22 AM, Forrest Oliphant <clawh...@gmail.com> wrote:
I stumbled upon this FBP group not really understanding the distinction between FBP, reactive, and other paradigms... I know enough to be dangerous, but I'm learning.

I am trying to understand the touch concept and pseudocode. In the clock example, what sends the touch and how does it flow through the graph?

One can send a touch when we believe an update will be sent very soon. Since touch indicates an update is coming, we often send a touch whenever we see a touch - i.e. the touch flows through the network like a wave, saying "there's an update coming! there's an update coming!" except that we don't need to repeat this if we've already reported it recently but have yet to send an update (e.g. when we receive touch on two different ports).

Of course, there is no point to sending a touch if we can just directly send the update.

So there are a few common situations in which we'd send the touch before sending the update:

(a) If an FBP process performs an expensive computation per IP, or waits on network, filesystem, or database queries that might take a while, it can send the touch before it begins to compute the update. 

(b) For splitter-processes (those which send on multiple ports), it can be useful to touch all the ports (or all but the first one, as a minor optimization) before before sending all the updates (starting with the first one). In the FBP context, each port might cause a wait for IPs (due to bounded buffer of IPs per port) so sending can be considered a potentially expensive operation.

(c) For zipper-processes (those which receive on multiple ports), it can be useful to send a touch the first time we see a touch on any port. It will be common to see touches on two or more ports before seeing updates on any of them. This allows us to wait for the updates on the ports that haven't been touched yet.

Note that processes may ignore touches. It's really up to each process to decide what it does when told there's an update coming. Similarly, it is ultimately up to each process to decide when to send a touch. There are some useful idioms, but nothing is set in stone. In the clock example in particular, a lot of cases are a hybrid of (b) and (c), so could use both idioms.

All synchronization is about waiting. With mutexes, we wait for another process to release the mutex. With transactions, we wait at least for the two or three phase commit. With promises or logic variables, we wait for single-assignment shared state to become specified.  With a clocked process or timeouts, logical delays, or scheduling, we wait on time. With Fant's clockless logic, we wait for an update to become available on every port. With temporal logic or synchronous reactive, we wait for a computational "instant" to complete.  With time warp protocol, we go ahead and compute optimistically but might perform a rollback if we discover we processed a message out of order - i.e. we're filling those waits with "probably-useful" computations to better utilize the computational resources (on average). With touches, we wait for the update that was promised (or at least an "oops, I was kidding" IP, i.e. cancel-touch).

If we want to minimize latency then waiting on time - on a clock or timeout or explicit logical delays - is the very worst option. Basically, every other option has the possibility of running as fast as the computation allows. Waiting on time means we only have the potential to run as fast as the clock allows.

Sometimes waiting on time is still a good option when we want to *control* latency, i.e. where minimizing variance in latency is more valuable than minimizing mean latency. (This happens often for real-time processes.) However, the best way to achieve this is logical delay - i.e. like sending a message at 1:00 saying "Hey, there's a meeting at 2:00". We aren't asking the recipient to go to a meeting right away, but are letting them know of an obligation with enough time to prepare and shift other tasks in their schedule. And that also gives us some time to change our minds about the meeting. (State-of-the-art for computation and UI is often like telling the computer: "Hey, there's a meeting at 2:00, get there", but saying it at 1:59:58 then begrudging the two seconds for the application to start. Is it any wonder our computers often seem unresponsive?)


Also, thinking about clocks, it would make sense to process the image for the next second. Then in the output you should show the processed image much closer to the actual second tick.

That sort of technique can work well - anticipation, double buffering. In the clock tick example, it works better than normal because clocks are very predictable (and so is everything in your computation chain). Logical delay can generalize that sort of advantage it to other domains.

Regards,

Dave

David Barbour

unread,
Jul 31, 2012, 2:38:41 PM7/31/12
to flow-based-...@googlegroups.com
Yes, I'm familiar with Fant's work. I agree there are similarities.

On Mon, Jul 30, 2012 at 6:45 AM, Matt <mm...@sympatico.ca> wrote:
Dave,

This touch idea sounds similar to the null convention logic described in "Computer Science Reconsidered" by Karl Fant.
In a nutshell the null convention logic is used to implement a "clock-less" system i.e. rather than relying on a central clock
to synchronize the processing of multiple inputs into a logic gate, a null state (yeah, a third state, besides the 0 and 1 state)
is emitted by the logic gate to indicate the "ready-ness" of the logic gate output.

Matt

Paul Morrison

unread,
Aug 1, 2012, 12:06:12 PM8/1/12
to flow-based-...@googlegroups.com
On 29/07/2012 7:58 AM, Dan wrote:
> First of all one port has one single role. If we need to pile
> different IPs with different types and roles and push them into a
> single port it means we have a "technical issue". For me it does not
> make any sense.
Hi Dan,

I didn't want to leave this statement unchallenged! Being able to mix
multiple IP types on one connection is a very powerful capability - why
would you want to give it up?! For a good example of its power, look
at the logic for the batch update, described in Chap. 9. Funny how
Chapter 9 keeps coming up in different discussions!

Regards,

Paul

Paul Morrison

unread,
Aug 1, 2012, 12:29:54 PM8/1/12
to flow-based-...@googlegroups.com
On 28/07/2012 7:38 PM, David Barbour wrote:
> Your approach to clocking may be cleaner than Forrest's, but still
> introduces considerable latency. E.g. if we chained 100 FBP processes
> in a row, and each was pushing only on clock signals at 30Hz, we'd
> expect 3.33 seconds to see a change on one end reach the other. There
> is, of course, always some latency involved in such chains, but
> avoiding a clocked logic could cut the latency down to milliseconds
> even for 100 processes.
Aha! It never occurred to me that anyone would assume I was going to
use this technique for more than one process in the chain - I assumed it
would be used only when the logic was constrained by the requirements of
the display device.

I have to dig into your touch logic a bit - haven't had time recently :-)

Regards,

Paul

Paul Tarvydas

unread,
Aug 1, 2012, 12:38:17 PM8/1/12
to flow-based-...@googlegroups.com
Having built my versions of FBP before seeing JPM's book, I came along a different path with the same result.

My components have (strongly typed) ports.

The ports are internally connected to a single input queue.

IP's are tagged with the port id when enqueued.

A component processes inputs one at a time, in order of arrival.

This method mimics the operation of hardware IC's and makes much of this discussion moot (this discussion seems to be conflating data-flow with FBP).

You can't have two inputs "arrive at the same time", one or the other is enqueued first. (This is also true in hardware where the trace length affects the travel time of a leading edge from one point to another. IIRC, ECL designers had to take the speed of light into account during design of PCBs).

When you have the possibility of two inputs arriving so closely spaced in time that you can't reliably predict which one will be first, you dust off the old TTL manuals and use race-condition handling techniques (e.g. state machines, etc.) to engineer a desired behaviour.

Since two inputs cannot arrive at the same time, this isn't dataflow.


This also leads to a different solution to the OP (if I understood the question correctly, which I barely remember :-) for creating a dynamic "clutch" on update requests.

Add a feedback loop to the refresh component. When the component finishes an update, it sends itself a blip and enters a waiting-for-blip-state.

In that state, it simply pulls update requests off of the queue (in order of arrival) and dumps them on the floor.

Once the blip arrives (advances to the front of the input queue), the component goes back to the process-updates state, wherein the next update request will cause a full update as above.

pt

Paul Morrison

unread,
Aug 6, 2012, 10:30:50 AM8/6/12
to flow-based-...@googlegroups.com


On Wednesday, August 1, 2012 12:38:17 PM UTC-4, paul.tarvydas wrote:
Add a feedback loop to the refresh component.  When the component finishes an update, it sends itself a blip and enters a waiting-for-blip-state.

In that state, it simply pulls update requests off of the queue (in order of arrival) and dumps them on the floor.

Once the blip arrives (advances to the front of the input queue), the component goes back to the process-updates state, wherein the next update request will cause a full update as above.


Hi Paul,

That's a great suggestion!  It does assume that the display component knows when it can accept another display request - if it does not know (i.e. it sends out the display refresh asynchronously), then I believe you have to use the clock idea I posted above.  Either way works...

If I read your post correctly, it also sounds as if all your components just have a single input connection, and input ports (in my sense) are basically tags on incoming IPs.  If I'm right, that certainly removes some of the concerns I run into, e.g. much of the potential for deadlocks, but I would think there are some functions that become more difficult, e.g. how would you handle Collate?  OTOH I may have misunderstood...?

Paul Tarvydas

unread,
Aug 6, 2012, 3:08:14 PM8/6/12
to flow-based-...@googlegroups.com
On 12-08-06 10:30 AM, Paul Morrison wrote:


On Wednesday, August 1, 2012 12:38:17 PM UTC-4, paul.tarvydas wrote:
Add a feedback loop to the refresh component.  When the component finishes an update, it sends itself a blip and enters a waiting-for-blip-state.

In that state, it simply pulls update requests off of the queue (in order of arrival) and dumps them on the floor.

Once the blip arrives (advances to the front of the input queue), the component goes back to the process-updates state, wherein the next update request will cause a full update as above.


Hi Paul,

That's a great suggestion!  It does assume that the display component knows when it can accept another display request - if it does not know (i.e. it sends out the display refresh asynchronously), then I believe you have to use the clock idea I posted above.  Either way works...

As I understood the OP, the clock wasn't there to time the refresh, it was there to "dump" excess requests (I might have misunderstood).  Kind of like a retriggerable one-shot in hardware - the first request triggers a time-out and any request that comes before that time is ignored.

My feedback version "free runs" as fast as it can, without responding to refresh requests that come "too fast".

If it needs to be synched to a time interval, then I'd add a 3rd input - a clock tick.  The waiting-for-blip state is actually three states - 1. waiting for blip or clock, 2. got blip, waiting for clock tick, 3. got clock tick, waiting for blip. 

In state 1, if a blip arrives, you goto state 2, or if a clock arrives, you go to state 3.

In state 2, when you get a clock tick, you goto the refresh (full update).  Every other input is ignored.  (Including excess clock ticks if the refresh is bogged down).

In state 3, when a blip arrives, you goto the refresh (full update).  Every other input is ignored.



If I read your post correctly, it also sounds as if all your components just have a single input connection, and input ports (in my sense) are basically tags on incoming IPs.  If I'm right, that certainly removes some of the concerns I run into, e.g. much of the potential for deadlocks, but I would think there are some functions that become more difficult, e.g. how would you handle Collate?  OTOH I may have misunderstood...?

I've never actually described it this way, but yes, all inputs funnel into the same (internal) queue after being tagged.[+]

Outwardly, it seems that you have multiple inputs, and they can be "strongly typed" (the editor / compiler can check that only allowable connections are made).

I don't see why Collate is a problem.  :-).  You and I probably have different mental models of what constitutes an IP - mine are particles, yours are waves (streams).

In my mental model, the inputs A and B to Collate are blips (single records, say).  To collate an A with a B, you have a three-state state machine: 10. wait for either an A or a B, 11. got an A, wait for B, 12. got a B, wait for A.  11 and 12 transition back to 10 and during the transitions they "collate" the A with the B and send it to the output port.

If A and B arrive "at the same time", it is indeterminate whether you enter state 11 or state 12, but, it doesn't matter, since upon entering either state, the next input will be the correct one to trigger a collate transition back to 10.

pt

[+] In the problem domain I've been working in - mostly embedded - the need for multiple inputs is so common that separating the "multiple inputs" into separate multiplexor boxes would make the diagrams unreadable.

Paul Morrison

unread,
Aug 6, 2012, 10:06:33 PM8/6/12
to flow-based-...@googlegroups.com
On 06/08/2012 3:08 PM, Paul Tarvydas wrote:
You and I probably have different mental models of what constitutes an IP - mine are particles, yours are waves (streams).

I think my IPs are particles too - they arrive at a process at a single moment of time - while a stream comprises all the IPs travelling across a particular connection.  The stream can also contain substreams (which can in turn be nested), where a substream is bounded by (non-data) bracket IPs.

In my mental model, the inputs A and B to Collate are blips (single records, say).  To collate an A with a B, you have a three-state state machine: 10. wait for either an A or a B, 11. got an A, wait for B, 12. got a B, wait for A.  11 and 12 transition back to 10 and during the transitions they "collate" the A with the B and send it to the output port.
I have to say that I don't have the concept of "waiting for A" - I just receive IPs from a connection (input port), and see what kind each one is.   For Collate, this forces me to have multiple input ports, as Collate checks the control fields on every IP, comparing the first (oldest) IP from each input stream, emitting the "low" IP, and then refreshing the IP from that input port.  Let's say I have a million A's, and 10 B's, I have to start by comparing the control fields of the first A and the first B, but I can't "read ahead" through the million As to find the first B.  So I guess I find I don't really understand the mental model you are describing... 

Oddly enough the use of Collate is described in Chap.9 (Chap. 9 again!).

Regards,

Paul

Ged Byrne

unread,
Aug 7, 2012, 3:36:10 AM8/7/12
to flow-based-...@googlegroups.com
IPs can be both a wave and a particle?  Are we straying into Quantum Computing here?


On Tuesday, 7 August 2012, Paul Morrison wrote:
On 06/08/2012 3:08 PM, Paul Tarvydas wrote:
You and I probably have different mental models of what constitutes an IP - mine are particles, yours are waves (streams).

I think my IPs are particles too...

Tom Young

unread,
Aug 7, 2012, 9:47:36 AM8/7/12
to flow-based-...@googlegroups.com
Is Morrison's cat dead or alive?
--
"...the shell syntax required to initiate a coprocess and connect its input and output to other processes is quite contorted..."
W. Richard Stevens [Advanced Programming in the Unix Environment, p441]

David Barbour

unread,
Aug 7, 2012, 9:58:22 AM8/7/12
to flow-based-...@googlegroups.com
That depends on whether `cat` was exploring a process file.

Paul Tarvydas

unread,
Aug 7, 2012, 10:22:28 AM8/7/12
to flow-based-...@googlegroups.com
Neither.

I'm working (slowly, in spare time) on a solution to the "collision" problem using FBP components and etherons...

Paul Tarvydas

unread,
Aug 7, 2012, 10:32:54 AM8/7/12
to flow-based-...@googlegroups.com
On 12-08-06 10:06 PM, Paul Morrison wrote:
...I have to say that I don't have the concept of "waiting for A" - I just receive IPs from a connection (input port), and see what kind each one is.   For Collate, this forces me to have multiple input ports, as Collate checks the control fields on every IP, comparing the first (oldest) IP from each input stream, emitting the "low" IP, and then refreshing the IP from that input port.  Let's say I have a million A's, and 10 B's, I have to start by comparing the control fields of the first A and the first B, but I can't "read ahead" through the million As to find the first B.  So I guess I find I don't really understand the mental model you are describing... 


I don't understand.  We must be miscommunicating, or, I am ignorant of some nuance of the Collate problem (not a problem I've often worked on).

Ch. 9 appears to show the idea of what I would call a "parser" - it inserts "tokens" (control fields) into the stream to help the downstream processing.  Compiler courses at U of T teach this method as a way of eschewing the use of (all in-core) parse trees.

The code in Ch. 9 shows what I would call a one-state state machine - each transition is triggered by an IP type, then each transition simply goes back to the top.

I don't see why what I've described cannot do this, also (unless the description is poor :-)...

Oddly enough the use of Collate is described in Chap.9 (Chap. 9 again!).


Is the code for Collate presented somewhere?  From what I understand, the code in Ch. 9 is only for Update.

pt

Paul Morrison

unread,
Aug 7, 2012, 12:52:33 PM8/7/12
to flow-based-...@googlegroups.com
I guess Chapter 9 is more about the /use/ of Collate than about its internal logic, which is sort of described by implication. The confusion may be coming from the fact that Collate combines two functions: the "collating" function, and the "parsing" function, which inserts delimiter IPs. I combine them because they use the same control fields, so you don't have to double up on the control fields IIP. Since Collate can be configured to only have one input port (input port element actually), you get your "parser" function without needing another specialized component.

If I understand your concern, maybe you were orienting on the parser part of the logic only, rather than on the merge part of the function. The JavaFBP Collate has one array input port, so it can merge any number of streams together based on up to 99 control fields IIRC, and of course inserts delimiter IPs into the merged stream.

Hth

Paul

Paul Tarvydas <paul.t...@rogers.com> wrote:

>On 12-08-06 10:06 PM, Paul Morrison wrote:
>> ...I have to say that I don't have the concept of "waiting for A" - I
>> just receive IPs from a connection (input port), and see what kind
>> each one is. For Collate, this forces me to have multiple input

>> ports, as Collate checks the control fields on /every/ IP, comparing

>> the first (oldest) IP from each input stream, emitting the "low" IP,
>> and then refreshing the IP from that input port. Let's say I have a
>> million A's, and 10 B's, I have to start by comparing the control
>> fields of the first A and the first B, but I can't "read ahead"
>> through the million As to find the first B. So I guess I find I don't
>> really understand the mental model you are describing...
>>
>
>I don't understand. We must be miscommunicating, or, I am ignorant of
>some nuance of the Collate problem (not a problem I've often worked on).
>
>Ch. 9 appears to show the idea of what I would call a "parser" - it
>inserts "tokens" (control fields) into the stream to help the downstream
>processing. Compiler courses at U of T teach this method as a way of
>eschewing the use of (all in-core) parse trees.
>
>The code in Ch. 9 shows what I would call a one-state state machine -
>each transition is triggered by an IP type, then each transition simply
>goes back to the top.
>
>I don't see why what I've described cannot do this, also (unless the
>description is poor :-)...
>

>> Oddly enough the use of Collate is described in Chap.9 (Chap. 9 /again/!).

Ged Byrne

unread,
Aug 7, 2012, 4:29:14 PM8/7/12
to flow-based-...@googlegroups.com
HI Forrest,

I see that you took the delay from string-join a couple of seeks after your original post.  May I ask what alternative solution you decided upon?

This is the first time I've looked at Meemoo and I am in awe.  What a great toolkit.

I've taken a look at the code and one thing confuses me: what is calling processLoop()? 

Have you considered adding a Render() input that receives a regular signal from a timer module?  This would provide you with a solution similar to the Time Grain Marker used in JSD:

JSD uses messages known as time grain markers which act like data streams but which contain timing information.  They are rough-merged with other data streams to control the arrival of messages and the timing of the execution of processes.  They are used to trigger actions within processes, start and stop processes and generally aid the synchronisation of processes. 

This would make the combine module timer agnostic, allowing an external strategy to be provided.

As with FBP JSD has just one input to a process upon which different types of message are placed.  I am assuming that calling the different inputs within MeeMoo is equivalent to passing the different methods in FBP/JSD.  

The key difference is that in MeeMoo one input may be provided before a previous input has completed which will lead to race conditions.  One way of avoiding this by having an internal process loop that processes an internal queue of inputs sequentially.  When inputs are called they are placed into this internal queue.  Is that what you are doing with processLoop()?  If so, have you considered making this the way in which all modules behave?

Making module instances entirely sequential makes everything much simpler.  If parallel activity is required then it is introduced explicitly using separate module instances.

Regards, 


Ged

Paul Morrison

unread,
Aug 7, 2012, 9:36:44 PM8/7/12
to flow-based-...@googlegroups.com
On 07/08/2012 10:22 AM, Paul Tarvydas wrote:

I'm working (slowly, in spare time) on a solution to the "collision" problem using FBP components and etherons...
What is an etheron?  Unless it's too complex to sum up in a few well-chosen words... :-)

TIA

Paul

Paul Morrison

unread,
Aug 7, 2012, 9:59:24 PM8/7/12
to flow-based-...@googlegroups.com
On 07/08/2012 4:29 PM, Ged Byrne wrote:
the Time Grain Marker used in JSD:

JSD uses messages known as time grain markers which act like data streams but which contain timing information.  They are rough-merged with other data streams to control the arrival of messages and the timing of the execution of processes.  They are used to trigger actions within processes, start and stop processes and generally aid the synchronisation of processes.


Sounds very similar to the clock tick strategy I described...


As with FBP JSD has just one input to a process upon which different types of message are placed.
Are we having a terminology problem here?!  In the discussion with Paul T. he also seemed to be advocating a single input port or input connection per process, and I still don't understand how you implement a Collate using only one input port...

As per Paul's request, here is some pseudocode for a Collate process merging 2 input streams (this generalizes very naturally to 'n' streams):
 
     <code>
     build an array of packets - with size of 2

     receive from IN1 and store received IP in first array slot
     receive from IN2 and store received IP in second array slot
     do forever
           if end-of-stream on IN1 and end-of-stream on IN2
                 break
           endif
           compare control fields of the two saved packets
           if control fields of the first packet are lower than or equal to the other
                 send packet in first slot to port OUT
                 do a receive on IN1
                 store received packet in first array slot
           else
                 send packet in second slot to port OUT
                 do a receive on IN2
                 store received packet in second array slot
           endif
     enddo
     </code>

    There are two more cases:
           a) if a receive gets end-of-stream, the saved packet control field values are essentially set to infinity; 
           b) where the above logic says "send", the packet being sent is always compared against the previous one  sent (if any), and delimiter (bracket) IPs are added ahead of it as appropriate

    Control fields are input via an IIP at another input port (e.g. call it CTRL) .

Ged Byrne

unread,
Aug 8, 2012, 2:01:12 AM8/8/12
to flow-based-...@googlegroups.com
Hi Paul,

Yes, and the problem is that I'm not expressing myself properly.

Perhaps the better way to say it is that there is only one "intake process" that executes on a single thread.  There are multiple ports, each with it's own stream, but there is only one process reading from those streams.

in JSD there are two types of merge: Rough and Fixed.  A rough merge has a single input buffer, or port, to which multiple processes send.  Messages are read in the order in which they are written.  Fixed merges have separate input buffers and messages can be read in a controlled order.

The multiple ports of FBP provide the fixed merge strategy.  The rough merges is the same as the control IP strategy that you describe for the Collate function.  Packets are read from a single port processed according to type.

Sorry about that.

Regards, 



Ged

Forrest Oliphant

unread,
Aug 8, 2012, 6:15:09 AM8/8/12
to flow-based-...@googlegroups.com
Ged,

In this simplified example http://meemoo.org/iframework/#gist/3293697 string-join's combine() does get called three times per second, but only sends if the string is different. I just noticed that this isn't so great for the clock example with the change of minutes or hours:

11: "12:17:55"
12: "12:17:59"
13: "12:18:59"   <- oops
14: "12:18:0"
15: "12:18:1"

So... issue not quite resolved there.

In the transform and combine image modules, I'm using the new browser function requestAnimationFrame to call processLoop. It calls processLoop not more often than the screen refreshes, and that works as a delay. Then processLoop only renders a new image if some variable has changed.

In examples with multiple image transformations, delaying the image by at least 1/60 of a second for every node introduces the race conditions that I'm trying to work around. I think that the touch concept that David explained might help.

The goal with the current design was: change a value, see the change. To do this I (effectively) made all of the inputs "hot."

I have thought about a render "bang" input, but it makes it a little more complicated to wire. If scale/rotate/translate were cold inputs, then you would have to hit render to see the change. In some transform module instances just the image will be changing, and others just the rotate value will be changing, and others more than one input will be changing at unpredictable intervals.

- Forrest

Paul Morrison

unread,
Aug 8, 2012, 9:35:27 AM8/8/12
to flow-based-...@googlegroups.com
On 08/08/2012 2:01 AM, Ged Byrne wrote:
> in JSD there are two types of merge: Rough and Fixed. A rough merge
> has a single input buffer, or port, to which multiple processes send.
> Messages are read in the order in which they are written. Fixed
> merges have separate input buffers and messages can be read in a
> controlled order.
>
> The multiple ports of FBP provide the fixed merge strategy. The rough
> merges is the same as the control IP strategy that you describe for
> the Collate function. Packets are read from a single port processed
> according to type.
Thanks, Ged,

That's a relief! Same concepts exactly - just different terminology!

Regards,

Paul

Paul Tarvydas

unread,
Aug 8, 2012, 11:36:42 AM8/8/12
to flow-based-...@googlegroups.com
Etheron = a unit volume of the ether.

In FBP, I am attempting to represent each etheron as an FBP component (i.e. 1,000's of components, strongly connected in a 2D grid).

Objects flying through the ether emit photons, which the ether propagates (applying some diminution on each propagation).  The photons report back (like bouncing radar waves) if they hit an object in the vicinity, and the object(s) monitors how close the other object is and performs "collision" physics if they touch.

Obvious, no?

:-)

pt

Paul Tarvydas

unread,
Aug 8, 2012, 12:02:39 PM8/8/12
to flow-based-...@googlegroups.com
OK, so after reading the code for Collate, I think I see some points of
miscommunication that are "too obvious" to each of us.

My components have multiple inputs and multiple outputs.

(The inner "funnel" queue is how I remove the need for preemptive
multi-processing. Ignore that for now.)

The main "obvious" non-stated point is, I *think*, that your ports
operate in a "pull" manner, whereas my ports are "push".

My code is reactive. When an input arrives, it reacts to it. It can
not (inherently) control "when" an input arrives.


I *think* that the Collate problem you describe can be paraphrased as:
Collate has two inputs A and B.

One A arrives, followed by a million B's.

Your solution to Collate requires that only one A and one B are held in
the Collate component at a time.

Your "pull" ports (automagically) regulate the influx of B's, pulling
only one at a time, processing it, then pulling another.

My "push" ports *appear* to have the drawback that they can't regulate
the influx of B's.

In a dumb solution, a million B's would pile up in the (hidden) input queue.


The solution is to think reactively - use a (network-like) protocol.

I *can* regulate the influx of B's by sending an upstream request for
each B. The response to the request is one B, or, EOF.

(Same for the A port).

So, I have two input pins A and B, and two (output) request pins ReqA
and ReqB going upstream.

In the domains where I've worked, e.g. embedded, reactive systems, it
makes much more sense to have as much asynchronous parallelism as possible.

The convenience overrides the slight inconvenience of having to add a
REQ/ACK protocol when you want to synchronize.

And, frankly, I like the idea that the Architect/Engineer has to
Engineer synchronization, explicitly (visually), into the solution.

That's, also, why I talk about state machines, whereas you talk about
case statements and loopers. (Reactive programming needs to track
state, state appears to be moderately implicit in the sequential code of
the pull model).

OTOH, if, 20 years ago I'd been forced to process bank records instead
of monitoring hardware sensors, then maybe I would have made my ports
"pull", also :-).


This raises an interesting question(s).

Are there two kinds of FBP? Push vs. pull?

Should (the Grand Unified) FBP support both, push and pull, ports?


[Oh, and then we can argue about multi-drop output ports and the
required semantics - also, quite useful in the reactive space. I feel a
lunch coming on :-].

Assuming, that is, that I've finally understood and have paraphrased
your problem correctly :-).

pt

Paul Tarvydas

unread,
Aug 8, 2012, 12:06:10 PM8/8/12
to flow-based-...@googlegroups.com
(Oh, and the photons communicate instantly back to their corresponding
objects using neutrinos or tachyons or "effect at a distance" phenomena).

Dan

unread,
Aug 8, 2012, 2:18:12 PM8/8/12
to flow-based-...@googlegroups.com
I remind you that on the Google group: "flowlang" (http://groups.google.com/forum/#!forum/flowlang) the topic: "Pull vs. push" was discussed quite often.
For instance, take a look to the post: https://groups.google.com/d/msg/flowlang/vu-y4PfcotM/SZmqdZjFrYAJ and to all subsequent posts regarding "pull vs. push", including mine (you can make a search yourself in flowlang Google group but also here on FBP group).

I consider this topic important for FBP because it is not just an "implementation" aspect. It affects the logic of the program.

I wished I would have had a sort of FBP network for these discussion groups, well integrated into a "semantic discussion(s) group(s)". Sometimes it is hard to follow the subjects and the topic title doesn't matter too much.

Regards,
Dan

Paul Tarvydas

unread,
Aug 8, 2012, 3:44:58 PM8/8/12
to flow-based-...@googlegroups.com
On 12-08-08 02:18 PM, Dan wrote:
> ...
> I consider this topic important for FBP because it is not just an
> "implementation" aspect. It affects the logic of the program.

This difference manifests itself in the "normal" (non-FBP) programming
world at the boundary between an operating system and its device drivers.

I was pushed towards push (reactive programming) by the fact that I had
to write very complicated device drivers.

No O/S at the time could handle the frequency of the hardware events we
were monitoring, using processes and context switches.

A lot of hard work had to be done at the device driver level.

The choices were: (1) write the code in ad-hoc assembler and C or (2)
find some other way.

We started writing reactive (state-based) modules to handle the
interrupting hardware ports.

We couldn't find a way to "hand off" the results to a preemptive process
(within the time limits), but we did find that if we treated the modules
themselves as if they were hardware-like interrupting ports, we could
write another layer of reactive modules to process those "software
ports" and so on.

After a while, the whole system got written this way and we simply threw
out the O/S.

The whole embedded application became one glorious set of layered,
structured device drivers (e.g. approx. 300 components, 128K of compiled
code).

pt

ps. GUIs are reactive problems
(http://www.youtube.com/watch?v=8vZ8Pi32oMo&feature=plcp). Network
protocols are reactive problems (hence, the difficulty of writing stacks
in non-reactive C). Web servers are reactive problems. Etc.

Tom Young

unread,
Aug 9, 2012, 6:54:13 PM8/9/12
to flow-based-...@googlegroups.com
I thought the following(triple buffering) might be a feasible approach to this problem:

http://www.drdobbs.com/bestofweb/QuickRead2.jhtml?KeepThis=true&TB_iframe=true&height=300&width=735

         Cheers,

                        -Tom


On Fri, Jun 15, 2012 at 5:04 PM, Forrest Oliphant <auf...@forresto.com> wrote:
Here is my latest Meemoo creation: http://meemoo.org/iframework/#example/rainbowclock

I have run across a funny issue in coding more complex images like this. In most of the modules, I want every input to potentially trigger a calculation (and output). But if several inputs change at the same time, I don't want to .

My solution was to put a 1000/30 ms timeout on every input. If more inputs are hit in that short timespan, the timeout is cleared. Example with the string-join.html module: https://github.com/forresto/meemoo-modules/blob/gh-pages/string-join.html#L36

This isn't optimal, because each module is now slowing down the data-flow. You can also see that in 14:transform, the image is rendered twice per second anyway, as the rotate input is hit before the image from 5:text makes it (because 7:string-join and 5:text modules have the timeout as well).

Pure Data uses "hot" inputs. I could do something like this that would only send the data when a "send" input is hit, but that would make for more complicated graphs.

Is there a better or standard data-flow way to solve this?

- Forrest



--
Thomas W. Young, Founding Member
Stamford Data, LLC
47 Mitchell Street, Stamford,  CT  06902

Phone: (203)539-1278
Email: TomY...@stamforddata.com


Paul Morrison

unread,
Aug 9, 2012, 7:43:55 PM8/9/12
to flow-based-...@googlegroups.com
What happened to Michelson-Morley? :-)  Or is your aether a metaphor for social networking?  Stranger things have happened! ;-)

[Long overdue for a lunch]

P.

Paul Morrison

unread,
Aug 9, 2012, 8:52:08 PM8/9/12
to flow-based-...@googlegroups.com
Comments interspersed below...  I think I'm suffering from some kind of paradigm shock.... ;-)


On 08/08/2012 12:02 PM, Paul Tarvydas wrote:
OK, so after reading the code for Collate, I think I see some points of miscommunication that are "too obvious" to each of us.

My components have multiple inputs and multiple outputs.

(The inner "funnel" queue is how I remove the need for preemptive multi-processing.  Ignore that for now.)
Happy to! ;-)


The main "obvious" non-stated point is, I *think*, that your ports operate in a "pull" manner, whereas my ports are "push".
As I believe I said before, maybe not too clearly, my image of FBP is both pull and push: 

- process A is connected to process B via a fixed-capacity connection C, with capacity 10 IPs, say.
- process A decides to generate and send a million IPs; the first 10 are stored in the connection; process A is then suspended (waits on a signal)
- at any time after the first IP is sent, process B starts doing receives.  The timing depends on how many processors there are, etc. 
- if at any time the connection goes empty, process B is suspended.
- these two types of suspend (send and receive) are independent of the number of processors; however, if there are more non-suspended processes than processors, they have to take turns (in JavaFBP, the JVM looks after this, so the JavaFBP scheduler only looks after connection-related scheduling).

So, is FBP "push" or "pull"?  I don't know, and I really don't feel it matters!  Sorry, Dan!


My code is reactive.  When an input arrives, it reacts to it. 
I assume you are saying that, when an input arrives,  code is invoked immediately to process it - presumably this is a subroutine.  Now, if there is no state data, it doesn't matter what thread this runs under.  If there is state data, it still doesn't matter, as long as the subroutine can get access to the state data somehow.   So, it seems to me that you are seeing a process/component as a collection of state data, not as a thread (correct me if I'm wrong).    So then (if I'm right), if  another IP arrives on the same input port/connection of the same process, the continuity between the two chunks of logic is straightforward - because they must arrive in a specific order.

Now I begin to see why multiple input ports on a single process are a problem (for several of the people participating in this discussion, apparently): since code gets executed immediately on the arrival of IPs, then it matters a lot in what sequence they arrive.  If they can arrive at the same time, it's even worse, as presumably you have to put locks in your code, and you have to worry about deadlocks.


It can not (inherently) control "when" an input arrives.
FBP does not control when an input arrives - it decides when to do the receive (or a send).  The state data is implicit in the fact that an FBP process has a single thread of control, and cannot wait on more than one event at a time.  Every time we have been tempted to weaken the latter rule, a) things get more complicated, and b) we discover it's not necessary anyway.




I *think* that the Collate problem you describe can be paraphrased as: Collate has two inputs A and B.

One A arrives, followed by a million B's.

Your solution to Collate requires that only one A and one B are held in the Collate component at a time.

Your "pull" ports (automagically) regulate the influx of B's, pulling only one at a time, processing it, then pulling another.
That's true - they do pull one at a time, but how long the "pull" takes depends on whether the connection is (temporarily) empty.


My "push" ports *appear* to have the drawback that they can't regulate the influx of B's.

In a dumb solution, a million B's would pile up in the (hidden) input queue.
My million B's don't pile up either - more and more upstream processes get suspended, until finally the file reader or the user is suspended.  FBP networks are self-regulating.
Parenthetically, my JavaFBP VolumeTest executes 100,000,000 sends and 100,000,000 receives in 4 mins. on my 4-processor desktop, and keeps all processors 99% busy!



The solution is to think reactively - use a (network-like) protocol.

I *can* regulate the influx of B's by sending an upstream request for each B.  The response to the request is one B, or, EOF.

(Same for the A port).

So, I have two input pins A and B, and two (output) request pins ReqA and ReqB going upstream.
We could do that in FBP - in fact FBP allows loop-type network topologies, which act very much like subroutines - but IMO the fixed-capacity connections make this unnecessary!

For a component that can be used in subroutine-like manner (loop topology) or as a flow-through process, see MCBSIM near the top centre of http://www.jpaulmorrison.com/fbp/image010.jpg


In the domains where I've worked, e.g. embedded, reactive systems, it makes much more sense to have as much asynchronous parallelism as possible.
I don't think we disagree on this - do we?


The convenience overrides the slight inconvenience of having to add a REQ/ACK protocol when you want to synchronize.
Sounds like you're saying you can do a Collate using your logic - which after all is the acid test!  I don't really care how complex a component is on the inside...


And, frankly, I like the idea that the Architect/Engineer has to Engineer synchronization, explicitly (visually), into the solution.
If you are saying that the default is asynchronous, and you should have to add any constraints explicitly, I think that's my philosophy too!


That's, also, why I talk about state machines, whereas you talk about case statements and loopers.  (Reactive programming needs to track state, state appears to be moderately implicit in the sequential code of the pull model).
So the discussion is really about what constitutes an FBP process: is it a separate control thread, or is it a collection of state data?  As long as our two approaches result in equally reliable and extensible systems, I probably don't care which we use.   Is yours more reactive?  Does mine provide better throughput?

I agree this discussion is important - and I sincerely hope that I've a) understood the difference, and b) explained it clearly.  The answer to both a) and b) is probably NO.


OTOH, if, 20 years ago I'd been forced to process bank records instead of monitoring hardware sensors, then maybe I would have made my ports "pull", also :-).


This raises an interesting question(s).

Are there two kinds of FBP?  Push vs. pull?
Hope not!


Should (the Grand Unified) FBP support both, push and pull, ports?
Maybe FBP should come in two major flavours - reactive and thread-oriented...?  Like iterative vs. recursive...?  Probably a bad example..



[Oh, and then we can argue about multi-drop output ports and the required semantics - also, quite useful in the reactive space.  I feel a lunch coming on :-].

Assuming, that is, that I've finally understood and have paraphrased your problem correctly :-).

pt

Assuming, that is, that I've finally understood and have paraphrased your problem correctly.   If not, we'll take over the Arms, armed with a pile of flip-charts and scads of coloured pencils... ;-)

Dan

unread,
Aug 11, 2012, 11:09:32 AM8/11/12
to flow-based-...@googlegroups.com
Paul Morrison wrote:
"So, is FBP "push" or "pull"?  I don't know, and I really don't feel it matters!  Sorry, Dan!"

Ok, let's go back to my favorite topic: "Push" vs. "Pull". I have mentioned in my previous topics two types of connections: the "material" (conveyor belt, pipe) and "potential" (electrical wire). This time I want to ask you what is your perspective regarding the following simple example:

A network of interconnected components is given. Among the components I have several ones that represent the function Sinus(x) named here Sin. It has an input port in and an output port out. This function is used as a component in several places. Comparing to imperative languages it is the equivalent of the function call Sin(x) from different places. "Calling a function" from several places, in FBP is equivalent with instantiating a component in that place of that model (function).

So, we have a model component: function Sin. We have two different places where this function is "called". In FBP we have in fact two different components (instances) called Sin1 and Sin2. Both of them are of the same model, i.e. Sin. Sin is not a model in the sense: source text code but it is compiled code. If somehow at runtime the code of function Sin (the model) is changing, I want Sin1 and Sin2 to change accordingly. In fact I want exactly the same code all the time at the place of Sin1 and Sin2 (not a copy). What I do expect is: in any place Sin is "instantiated" the original Sin function to be used.

My question to you is: what is the relationship in the FBP network diagram between the component Sin (model) and Sin1, Sin2?

In my opinion the component Sin (source) is connected via a "potential" connection ("electrical wire") with Sin1 and Sin2. Sin is a model in a compiled version and a unique source of Sin1 and Sin2 that are "receivers" (value receivers). Each time Sin is changed, instantly Sin1 and Sin2 are changed like the electrical potential applied to one end of an electrical wire changes the potential on the other end. Effectively nothing is changed in our FBP network because the value of Sin (i.e. code) will be "retrieved" at different places at demand.

I've said with other occasion that the implementation of the "potential" connection is realized using "pull" method. This is exactly what happens in the imperative languages when a function is called: the context is saved on / loaded from the stack and the function is called and executed from the single and unique place where it resides in memory.

In our case (FBP) it is no "proper moment" in time when to "push" the value of Sin into place of Sin1 and Sin2. The function Sin (i.e. the component) is "called" (i.e. pulled at demand in different places). Obviously nobody expects to really duplicate the code of Sin at the place of Sin1 and Sin2. Effectively when the value of Sin (I am referring to the code not the output) changes nothing happens.

So what are Sin1 and Sin2 in FBP? In my opinion they are just "duplicates" of Sin that are connected continually with their source (function Sin). Sin1 and Sin2 bring the value of Sin (i.e. the function code) in different places (i.e. where Sin1 and Sin2 are placed in the network). What differentiate Sin1 from Sin2 from Sin? It is the context i.e. the input and output values. These values are saved on / loaded from the stack in imperative languages. The context in FBP case is given by the connections.

Because Sin in English has a real meaning, you can replace it in my previous example with Cos :-). Imagine this text was written in "FBP style". What you have to do is to replace the value of the single source, known before as Sin, with the value and name of Cos. If this text was an html page (and it is) and later on you want to do the change, you do it in only one place (principle DRY). How are the "instances" connected to their unique source (model)? Of course with an "electrical wire" and not a pipe.
The value is pulled on demand. When the demand is created? As a result of a push at the place of an instance; in my example when  a value arrives at the input of Sin1 or Sin2).

I have chosen this very common example (of what is a "function call") to demonstrate the value of the notions I have introduced before. You might say this is just a matter of implementation but I think it is not just that.
I am eager to know your perspective.

Regards,
Dan

Paul Morrison

unread,
Aug 11, 2012, 12:10:06 PM8/11/12
to flow-based-...@googlegroups.com
Sorry, Dan (again).  I feel there is something going on here that I am not grasping!

For me, Sin and Cos have *nothing* to do with push or pull :-)

I probably wouldn't use an FBP component for Sin or Cos as these subroutines (methods) are already black-boxy and synchronous, but let us suppose that I do want to write a component that accepts a stream of IPs containing angles (in radians, say), and, for each incoming IP, outputs an IP containing a sine (or cosine) value.  Are you OK with this?

If this is acceptable, then the *component" is Sin, and the multiple occurrences are "processes", each with its own thread of control, and they might be called Sin1, Sin2, Joe, Sam, etc.  Every Sinx process is executing the *same* code, but has its own Java or C# thread, its own stack, therefore its own local storage, and its ports will be connected to different processes (usually).

When you define a network of processes and their connections, you have to name the processes and ports... or you could do what we did in AMPS, which was to name the connections (and ports, except we numbered them then).  Process names (or connection names) are only of interest at the network level; port names have to be "agreed" between the component code and the network definition.

I get the feeling that you may be thinking of a more complex case, where you want to be able to load component code at run time.  If so, the above model obviously has to be extended.  I do talk about dynamic modification of networks in my book - and we did implement a number of special cases of this in various FBP implementations.  Still, I really don't see what this all has to do with push or pull.  :-)  If you looked at my previous post in response to Paul T., maybe you (or someone else) can figure out where the miscommunication is coming from!

Regards,

Paul M.

Brad Cox

unread,
Aug 11, 2012, 12:45:42 PM8/11/12
to flow-based-...@googlegroups.com
Re: My question to you is: what is the relationship in the FBP network diagram between the component Sin (model) andSin1Sin2?

Perhaps std OO terminology might help? Sin(model) isn't a component, but a component *class*. Sin1 and Sin2 are components; i.e. *instances* of a component class. Instances may  have state (not relevant for sin/cos, but yes for average or wordCount) and can thus differ from other instances even though sharing the same class.

Afraid I still can't get away from the feeling that conveyor belts that can haul power and/or materials is a bad idea. 

Paul Morrison

unread,
Aug 11, 2012, 1:25:54 PM8/11/12
to flow-based-...@googlegroups.com
I'm with you all the way, Brad, except maybe for calling Sin1 and Sin2 "components" - but I'm fine with "instances of a component class"!  This is exactly the area I was struggling with in the Preface to the 2nd Edition!  Maybe we should go with "island" :-)

And I agree about the last sentence too!  Power and materials have totally different behaviour!

Regards,

Paul

David Barbour

unread,
Aug 11, 2012, 2:42:06 PM8/11/12
to flow-based-...@googlegroups.com
On Thu, Aug 9, 2012 at 5:52 PM, Paul Morrison <paul.m...@rogers.com> wrote:

So, is FBP "push" or "pull"?  I don't know, and I really don't feel it matters!  Sorry, Dan!

FBP is "push", with bounded buffers. 

 

Now I begin to see why multiple input ports on a single process are a problem (for several of the people participating in this discussion, apparently): since code gets executed immediately on the arrival of IPs, then it matters a lot in what sequence they arrive.

I think that is not the issue. Rather, people are assuming the ability to perform at least one of:

* test whether an input port is empty
* wait on more than one input port
* merge multiple input streams based on arrival time

Any of these  techniques will result in non-deterministic computation, i.e. allows race conditions in the FBP network as a whole. You could avoid non-determinism with Kahn processes or a like discipline - not allowed to test for empty, and all merges modeled by processes. Such designs trade latency for easier reasoning. Though, cyclic FBP models have potential to deadlock on bounded buffers, which can result in more difficult reasoning.

OTOH, non-determinism is not a "problem" if introduced explicitly and in a controlled manner.


Parenthetically, my JavaFBP VolumeTest executes 100,000,000 sends and 100,000,000 receives in 4 mins. on my 4-processor desktop, and keeps all processors 99% busy!

That seems quite poor for performance, even in Java. I.e. you're breaking it down to 420k IPs per second, even after buffering. Granted, I don't know the quality of your processors, the nature of the benchmark, or the size of your bounded buffers. But Erlang, Akka, AsyncFP, etc. tend to benchmark in millions of messages per second. 


Maybe FBP should come in two major flavours - reactive and thread-oriented...?  Like iterative vs. recursive...?  Probably a bad example..

Egads, no. Let FBP be FBP, and let reactive be reactive, and simply understand when you're modeling one in the other.  They are related models, but subtle differences in the kernel can result in large differences in emergent structure.

Regards,

Dave
 

John Cowan

unread,
Aug 11, 2012, 4:11:22 PM8/11/12
to flow-based-...@googlegroups.com
David Barbour scripsit:

> > So, is FBP "push" or "pull"? I don't know, and I really don't feel it
> > matters! Sorry, Dan!
> >
>
> FBP is "push", with bounded buffers.

I would say it is pull on the input side and push on the output side.

--
Real FORTRAN programmers can program FORTRAN John Cowan
in any language. --Ed Post co...@ccil.org

Paul Tarvydas

unread,
Aug 11, 2012, 4:41:33 PM8/11/12
to flow-based-...@googlegroups.com
> FBP is "push", with bounded buffers. 
...
 
From PaulM's description, I would agree.
 
I am using a variant that has 0-length bounded buffers (i.e., the wires are "stupid" and cannot tell the upstream to slow down).
 
> Let FBP be FBP, and let reactive be reactive,
 
If FBP is "push", but not reactive, what is the difference between push and reactive?
 
I don't remember when I started using the term "reactive", but it's been more than a decade.  The recent wikipedia entry does not agree with my notion - they seem to conflate "contstraint based" (too automagic) programming and "reactive".
 
My kind of components "wait" on any - and all - inputs, without the ability to query their emptiness or fullness.  "Here's an input, deal with it".  No priorities, no way to rearrange input order.  (They can accept an input, then ignore it by dropping it on the floor).
 
 
And, fwiw, I do think of the flow as "electronic", but not based on potential - based on narrow pulses (pulse trains) instead.
 
I agree with PaulM that the architecture (diagram) should not be altered at runtime. 
 
For dynamic behaviour, I developed a notion of "sockets" (akin to IC sockets), where one could pass components around and plug them into sockets (assuming pin-compatibility, at least for a subset of pins (duck typing)).  None of the production apps used this notion - it seemed that it was always preferable to create a static architecture and deliver it.  Much like in Engineering blueprints, e.g. a blueprint for a specific bridge does not show replaceable chunks.  I would suggest that this is where OOP has gone off the rails - increased flexibility does not lead to reliable design.  Cutting and pasting diagrams is a powerful form of reuse (whereas, cutting an pasting textual code does not work well).
 
pt
 

Paul Morrison

unread,
Aug 11, 2012, 5:31:09 PM8/11/12
to flow-based-...@googlegroups.com
On 11/08/2012 4:11 PM, John Cowan wrote:
> I would say it is pull on the input side and push on the output side.
That's my feeling too!

Paul Morrison

unread,
Aug 11, 2012, 5:33:59 PM8/11/12
to flow-based-...@googlegroups.com
On 11/08/2012 2:42 PM, David Barbour wrote:

Parenthetically, my JavaFBP VolumeTest executes 100,000,000 sends and 100,000,000 receives in 4 mins. on my 4-processor desktop, and keeps all processors 99% busy!

That seems quite poor for performance, even in Java. I.e. you're breaking it down to 420k IPs per second, even after buffering. Granted, I don't know the quality of your processors, the nature of the benchmark, or the size of your bounded buffers. But Erlang, Akka, AsyncFP, etc. tend to benchmark in millions of messages per second. 


My guess is that we are comparing apples and oranges.  Still, it would be great if someone could take my code and speed it up!  I've probably disimproved John's original version quite a bit!

John Cowan

unread,
Aug 11, 2012, 6:17:43 PM8/11/12
to flow-based-...@googlegroups.com
Paul Morrison scripsit:

> My guess is that we are comparing apples and oranges. Still, it
> would be great if someone could take my code and speed it up! I've
> probably disimproved John's original version quite a bit!

Hardly. I designed it to be easy to write, robust, and easy to change.
Performance wasn't a consideration: I figured that overall JVM performance
improvements would take care of such difficulties.

--
Here lies the Christian, John Cowan
judge, and poet Peter, http://www.ccil.org/~cowan
Who broke the laws of God co...@ccil.org
and man and metre.

David Barbour

unread,
Aug 11, 2012, 7:06:15 PM8/11/12
to flow-based-...@googlegroups.com
On Sat, Aug 11, 2012 at 1:41 PM, Paul Tarvydas <paul.t...@rogers.com> wrote:
> Let FBP be FBP, and let reactive be reactive,
 
If FBP is "push", but not reactive, what is the difference between push and reactive?

Your hypothesis is untrue. Push vs. pull is not the dimension that differentiates FBP and reactive programming. Reactive may also require push-based implementations, and often does. 

If you are interested in distinguishing reactive models from FBP, I suggest you look up synchrony hypothesis, discrete event calculus, temporal logic (e.g. as done by Dedalus). A critical feature of (correct) reactive systems is that we can observe two dependent values changing at the same time.  I.e. it's about a formal model of synchronous concurrency. We cannot express this directly in FBP, though since both FBP and reactive models are general purpose we can (with a little discipline) adequately model either in the other. 


I am using a variant that has 0-length bounded buffers (i.e., the wires are "stupid" and cannot tell the upstream to slow down).

That sounds more like unbounded buffers, i.e. like actors model except a bit more orderly.  1-length buffers are equivalent to Ada rendezvous. 

 
I agree with PaulM that the architecture (diagram) should not be altered at runtime.

I can think of many reasons to alter a diagram at runtime - e.g. to model extensions and plugins, linking, service brokering, compilation, configuration, runtime service discovery, state and strategy patterns, progressive disclosure models, object capability security patterns, live programming, runtime upgrade. But I do prefer it should occur in a disciplined manner at well defined boundaries, i.e. not ad-hoc changes like OO allows. For RDP, I model dynamic behaviors in terms of a reactive `eval`:

    eval :: ((Behavior :: Inputs ~> Outputs) x Inputs) ~> Outputs

This probably wouldn't work so well in FBP, since FBP processes may easily accumulate state with no easy way to transition that state to the next dynamic network. Developers would need to be a lot more disciplined in their designs. But my RDP ensures that the behaviors are stateless, i.e. all state is pushed to outside databases and grids.

David Barbour

unread,
Aug 11, 2012, 7:10:04 PM8/11/12
to flow-based-...@googlegroups.com
It does sound appealing.

Dan

unread,
Aug 12, 2012, 9:49:53 AM8/12/12
to flow-based-...@googlegroups.com

Paul M.: “Sorry, Dan (again).  I feel there is something going on here that I am not grasping!”

I am afraid so :-).

“Pull” and “push” are a way to implement two different aspects in FBP. Strictly speaking everything is “push” but for various reasons “pull” is the only way to implement the situation I have described for “potential” connections where I want the same value (content of a component) in different places at the same time.

A->B means B is continually connected with A and each time A is changing B is following A instantly. B has the same value with A all the time. I don't know when to push the value of A into B, because I have to do it all the time. So what am I doing? I do nothing. I will “pull” A into B only at demand. This is lazy programming. Demand is created in the downstream (i.e. at B). Now you can imagine A and B with multiple ports and the connection is A.o1 -> B.i1. Demand is created in B as a result of an IP that is coming into B through another port e.g B.i2.

A “function call” is an instance of a model (function). The model is at runtime! Its value is the function code (compiled). The instance (“function call”) is connected to the model with a “potential” connection. The model could contain data too. Data could be part of a model. Also data mixed with functions could be part of a model. It does not matter, the logic remains the same.


Paul M.: “For me, Sin and Cos have *nothing* to do with push or pull :-)
I probably wouldn't use an FBP component for Sin or Cos as these subroutines (methods) are already black-boxy and synchronous[...]”

Even if we can find versions of Sin and Cos already made and packed as subroutines in C++, Java or whatever else, it does not mean that a FBP style of Sin and Cos will not do. FBP is not just coordination language. Sin and Cos were used as examples. You can name them as you want and imagine they are complex functions written fully in “FBP style” all the way down to the atomic components.


When building a FBP program why to stop to a certain granularity? Why not going to the finest granularity? Why not having a full FBP compiler and language? Why to be obliged to use Java, C, C++ or other language for the lower granularity components?

My example was not in the context of a FBP middleware that has subcomponents implemented in another language. This is good to have and must to have but not this is the issue. I was talking about a full FBP environment. Such a platform is stackless or it works with stacks but not in the form we know from the imperative programming.


Paul M.: “If this is acceptable, then the *component" is Sin, and the multiple occurrences are "processes", each with its own thread of control[...]”

Not necessarily. In a compiled version of the component, Sin will not be a process with its own thread of control but it could be. Obviously this is not necessary but it does not mean automatically that my FBP style of Sin is a function that uses the same calling protocol as in imperative languages (using standard calling stack mechanism). This is the main issue I was discussing about.


Paul M.: “I get the feeling that you may be thinking of a more complex case, where you want to be able to load component code at run time.”

Yes, I do. Even if this is not the case, the logic has to deal with this aspect. For instance, the compiler has to build code for loading the component at runtime. The largest component loaded is the entire program that has to run. Why not being able to load at demand the components at runtime?


Paul M.: “Still, I really don't see what this all has to do with push or pull.  :-)”

It has because you pull the component that is loaded. The frozen component from the hard disk will not have any "initiative" to load by itself in the memory. It is dead. Another component will have the initiative.


Brad Cox: “Perhaps std OO terminology might help? Sin(model) isn't a component, but a component *class*. Sin1 and Sin2 are components; i.e. *instances* of a component class.”

This is totally wrong. I think this misconception is widely spread. Sin(model) is a component (instance) and not just a component class that usually it is associated with the source code (text). A model could be instance in the same time. You are used with the terms from C++: something is an instance of a class. So a class is not an instance. In C++ this is true by definition. In my case it is not. A model is a class and can be an instance. The class is another form of an instance of type singleton. I know, it's difficult to grasp :-). Between the class/model (that exists as source code) and the runtime model (as instance) is a relationship. One it is transformed into another by a compiler. Just the underlying base is changed; essentially the information is the same.


Maybe I will treat this in detail into a another topic but I will give you a short example here. Let's suppose we are developing a game with ships, cars, characters and a lot of other entities. We have more ships of the same kind. A model of a ship is not designed entirely in code (e.g. C++). It contains code and data altogether. I need more replicas of this object in my game. How am I doing that? If you ask the computer game programmers they will answer you that they are designing behavior and data partially in C++ (with classes), partially in scripts, partially in data files. Scripts are used to make the code developing easier for non-programmers but also to “configure” complex constructs that contains code and data (the ship itself). In the end they will have a real component at runtime (i.e. an instance) that is used as a model. This model (template) is cloned. The cloning process could be very complex (unfortunately) because it could contains logic of what is really duplicated and what is used in common (common data from the model that is referred in the instance). Besides that, the cloning has to deal with the different context (i.e. connections).


Brad Cox: “Instances may have state (not relevant for sin/cos, but yes for average or wordCount) and can thus differ from other instances even though sharing the same class.”

Instances can have state and also the model can have state. Including our functions sin and cos may have state. Imagine the sin and cos calculated using tables and interpolation method. They have state (that in this case is not modified but shared).

The problem is that you see a “class” at compile time as text code and an instance at runtime as bytes. In general terms a model is a class (text source code) and it could be an instance (template at runtime to clone). There is no fundamental difference but the form of existence. Of course the instance (at runtime) is prepared (compiled) for a certain type of microprocessor.


Brad Cox: “Afraid I still can't get away from the feeling that conveyor belts that can haul power and/or materials is a bad idea.”

Paul M.: “And I agree about the last sentence too!  Power and materials have totally different behaviour!”

I don't get it. The conveyor belt is used as a metaphor. What's wrong with that? Somebody has to be in charge with transportation of the IP from one place to another. This is just the logic because it does not happen like this in reality. All the time in reality the transportation of data from one place to another is through a copy process. Nothing moves effectively and if the entire program runs on the same computer that data is not moving at all. It is copied (fetched) in the microprocessor, interpreted, executed and saved back in the memory but nothing really moves. Conveyor belt remains a metaphor.


Paul Tarvydas: “If FBP is "push", but not reactive, what is the difference between push and reactive?”

Yes, I have the same question too. I don't see the difference.


Paul Tarvydas: “And, fwiw, I do think of the flow as "electronic", but not based on potential - based on narrow pulses (pulse trains) instead.”

In order to eliminate any confusion, if you think of the flow as based on pulses then it is about “push”. When I was explaining the “potential” type of connection it was “pull” (the initiative belongs to a downstream component). “Potential” type of connection brings an information from one place to another but the receiver can not modify it in any way without producing a short circuit. It is read only. It is like the emitter applies a potential to the “wire” and on the other end the receptor tries to apply a different potential.


Paul Tarvydas: “I agree with PaulM that the architecture (diagram) should not be altered at runtime.”

I completely disagree. I do not understand why do you think a program should be static. I am bringing again the example of computer games because they are so dynamic. What is static there? Everything can change and dynamically interconnect or disconnect. It is mandatory to be dynamic. How to deal with static networks as long as the game application itself is dynamic. Maybe you can explain to me how you can create a complex computer game application without having a dynamic network. What you try to simulate in the game is dynamic by definition. The game application could be quite different from a business application.


Regards,

Dan

Paul Morrison

unread,
Aug 12, 2012, 11:17:56 AM8/12/12
to flow-based-...@googlegroups.com
On 12/08/2012 9:49 AM, Dan wrote:
Let's suppose we are developing a game with ships, cars, characters and a lot of other entities. We have more ships of the same kind. A model of a ship is not designed entirely in code (e.g. C++). It contains code and data altogether. I need more replicas of this object in my game. How am I doing that? If you ask the computer game programmers they will answer you that they are designing behavior and data partially in C++ (with classes), partially in scripts, partially in data files. Scripts are used to make the code developing easier for non-programmers but also to “configure” complex constructs that contains code and data (the ship itself). In the end they will have a real component at runtime (i.e. an instance) that is used as a model. This model (template) is cloned. The cloning process could be very complex (unfortunately) because it could contains logic of what is really duplicated and what is used in common (common data from the model that is referred in the instance). Besides that, the cloning has to deal with the different context (i.e. connections).
Maybe game-building is the image that informs Dan's comments about this and other topics.  I have to admit that I don't have a game-building background - or even game-playing, so I have never given any thought to how you would write a game in FBP.  IMO FBP is about reconfigurability, so I can't see using the network level to allocate and deallocate ships, or transient objects generally - these would be more appropriately handled using IPs.  And remember that IPs can have methods hung off their content class objects, so IPs still give you a lot of capability.  OTOH FBP might be perfect for setting up a "game board", e.g. cities with roads connecting them, railway lines, etc., with perhaps "slow" configuration changes during the game... 

However, as you can probably tell, I am out of my depth here :-)  Should we open up the discussion to include game-building, or would that be better handled elsewhere?  Comments?

Paul Morrison

unread,
Aug 12, 2012, 11:32:20 AM8/12/12
to flow-based-...@googlegroups.com
On 12/08/2012 11:17 AM, Paul Morrison wrote:
> OTOH FBP might be perfect for setting up a "game board", e.g. cities
> with roads connecting them, railway lines, etc., with perhaps "slow"
> configuration changes during the game...
I think I have this backwards! :-( I forgot about the thread of
control in the processes: you would want ships to be able to execute
logic asynchronously with each other - and it is probably not meaningful
to have a city executing asynchronously with other cities... I guess
gaming really is a different world from the one I'm used to... :-)

Brad Cox

unread,
Aug 12, 2012, 11:46:36 AM8/12/12
to flow-based-...@googlegroups.com
I know, it's difficult to grasp :-). 

No, its difficult to explain clearly. :-(

Dan

unread,
Aug 12, 2012, 2:08:27 PM8/12/12
to flow-based-...@googlegroups.com
You are right, it's difficult to explain something for different people with different backgrounds and different experiences, to be short enough and not be boring in the same time. Nothing is easy. Besides that we are discussing ideas that might not have a big value or they might. Who knows?

Dan

ifknot

unread,
Aug 12, 2012, 4:35:38 PM8/12/12
to flow-based-...@googlegroups.com
Concur, FBP as described by PM is undeniably both.

But given that it is both and non-deterministic on a free running multicore system then components need some awareness of latency in the system and some way of reacting to it, further components need some awareness of deadlock and a mechanism to handle same.

I have a 'toy' FBP implementation for experimentation that uses FIFOs (type safe unique_ptr ips - no mixing here) but prior to yielding, promotes the appropriate producer/consumer task priority so that it gets preference in the threadpool - early evidence is that it increases throughput (depending on nature of graph) 10-15%. Hoping to expand on this to make components deadlock aware as by virtue of my design decision of type safe connections my system disallows multiple inputs at one port and is, therefore, vulnerable.

Further, given latency awareness in an FBP graph I am currently playing with automatic inverse multiplexing (http://en.wikipedia.org/wiki/Inverse_multiplexer) to opaquely deal with slow components by focusing processor(s) time preferentially upon them. I'm not sure the overhead is worth it, particularly where ip (re)ordering is concerned but it's fun!

John Cowan

unread,
Aug 12, 2012, 4:41:45 PM8/12/12
to flow-based-...@googlegroups.com
Dan scripsit:

> When building a FBP program why to stop to a certain granularity? Why not
> going to the finest granularity? Why not having a full FBP compiler and
> language? Why to be obliged to use Java, C, C++ or other language for the
> lower granularity components?

Primarily because an FBP language is a lazy pure functional language, like
Haskell. Not everyone wants to program in Haskell.

--
When I'm stuck in something boring John Cowan
where reading would be impossible or (who loves Asimov too)
rude, I often set up math problems for co...@ccil.org
myself and solve them as a way to pass http://www.ccil.org/~cowan
the time. --John Jenkins

Paul Tarvydas

unread,
Aug 12, 2012, 4:45:35 PM8/12/12
to flow-based-...@googlegroups.com
On 12-08-11 07:06 PM, David Barbour wrote:
...

> I agree with PaulM that the architecture (diagram) should not be altered at runtime.

I can think of many reasons to alter a diagram at runtime - e.g. to model extensions and plugins, linking, service

On 12-08-12 09:49 AM, Dan wrote:
I completely disagree. I do not understand why do you think a program should be static. I am bringing again the

I am not giving my *opinion*.

I am stating my *observations*,  after some 20 years of working with this paradigm, delivering commercial products.

After I got real experience with FBP, I (and everyone else using this) began to design differently. 

Just about all of my early assumptions were proven wrong by experience.

1. I expected to develop a vast library of reusable components.  Wrong.  FBP's form of architectural reuse is much more powerful.  You don't really need a library.  A "cookbook" of "patterns" is all you need (and/or just stealing ideas from existing diagrams).

2. At first, we drilled down "too deep".  A component for "+", "-", "!", etc.  Amateur mistake.  Bloatware.  (And, probably, the main reason why detractors say that programming with diagrams cannot work.  BLUB - they can't imagine what FBP does express).  [Prograph tried to express too many text-level programming constructs with its diagrams.]

3. We put types on the ports and wires. 

4. Our "internal" languages provided full-blown variable scoping, when simple, old-BASIC-like global variables were sufficient (most components are composed of only a handful of lines of code - global variables encapsulated within the components are fine, completely visible and don't cause spaghetti).

5. We built diagram editors that "helped" you by doing type-checking at edit time.  About as bad an (thankfully dead) idea as structured editors for textual code.

6. We started using GOTO again, in spades (what else is a state machine, but a wonderful form of goto?).

7. We built editors that allowed us to use "any shape" for components.  Duh.

8. I certainly did not anticipate that one would "integrate" the system before writing the code.

... and so on ...

By my count, there's only a handful of people here who have used FBP for an extended period of time and have delivered non-toy production systems and have earned a living doing so.

I don't see any of them advocating dynamic modification of diagrams.  Why?

Did you experience "self modifying code" back in the days of assembler?  Was that a good idea?

pt

David Barbour

unread,
Aug 12, 2012, 4:57:53 PM8/12/12
to flow-based-...@googlegroups.com
On Sun, Aug 12, 2012 at 1:35 PM, ifknot <ifk...@hotmail.com> wrote:
Concur, FBP as described by PM is undeniably both.

I deny it.
 

On Saturday, 11 August 2012 14:31:09 UTC-7, Paul Morrison wrote:
On 11/08/2012 4:11 PM, John Cowan wrote:
> I would say it is pull on the input side and push on the output side.
That's my feeling too!

David Barbour

unread,
Aug 12, 2012, 6:10:24 PM8/12/12
to flow-based-...@googlegroups.com
On Sun, Aug 12, 2012 at 1:45 PM, Paul Tarvydas <paul.t...@rogers.com> wrote:

2. At first, we drilled down "too deep".  A component for "+", "-", "!", etc.  Amateur mistake.

Developers make the same amateur mistakes in many other paradigms. E.g. badly reinventing a fair bit of C++ `boost` before realizing there are dedicated libraries for it. Failure does not mean that the design is wrong, though it does suggest it was wrong for your circumstances and budget. This is really the job of a language designer, who can provide appropriate tools, compilers, optimizers, and a suitable model for foreign resources or FFI. 


5. We built diagram editors that "helped" you by doing type-checking at edit time.  About as bad an (thankfully dead) idea as structured editors for textual code.

Let me guess: you enforced structural constraints on the edits, rather than simply highlighting the regions and wires where type-checks were failing or using types to guide suggestion boxes. Type checking at edit time can be great, but there are many more ways to foul up than to get it right. 
 

By my count, there's only a handful of people here who have used FBP for an extended period of time and have delivered non-toy production systems and have earned a living doing so.

I don't see any of them advocating dynamic modification of diagrams.  Why?

FBP has been primarily applied in circumstances where static networks seem adequate. E.g. there are no browsers, command and control systems, multi-user dungeons, or video games developed in an FBP style. By avoiding problems that strongly suggest dynamic networks, you can fold any remaining dynamism into the procedural component layer.
 

Did you experience "self modifying code" back in the days of assembler?  Was that a good idea?

Support for dynamic models does not imply the unstructured, stateful changes that caused problems with self-modifying assembler. 

ifknot

unread,
Aug 13, 2012, 2:22:45 AM8/13/12
to flow-based-...@googlegroups.com
Mens rea?

Dan

unread,
Aug 13, 2012, 9:37:56 AM8/13/12
to flow-based-...@googlegroups.com
Paul Tarvydas: "At first, we drilled down "too deep".  A component for "+", "-", "!", etc.  Amateur mistake.  Bloatware.  (And, probably, the main reason why detractors say that programming with diagrams cannot work.  BLUB - they can't imagine what FBP does express)."
Dan: Amateur mistake? Bloatware? No way. The lack of a FBP compiler able to translate a FBP source code into binary code with the finest granularity forces you to use other languages and platforms as middleware. That creates bloatware not the fact we are drilling down "too deep". Never is too deep.

Maybe you imagine a component "+" with ports, IPs with type checking and all the stuff implemented in whatever language. Of course it is bloatware. Does it proves that going all the way down to the tiniest component is a wrong idea? No, not at all. Your C++, Java etc. middleware you have to build will interpose and create the bloatware. We don't need it. A good FBP compiler will translate the code into what it is really needed for a specific microprocessor. In case of our "+" component I do expect something like this:
mov eax, v1;
mov ebx, v2;
add eax, ebx;
mov rez, eax;

Also I do expect the FBP source code to look like this:
rez <- v1 + v2; (notice "<-" and not "=")
rez = v1 + v2; //this would be wrong

I do not expect definitions like this:
component "+" :
{
    inports:
        float op1;
        float op2;
    outports:
        float rez;
    connections:
        ... and so on
}
This is bloatware indeed.

Paul Tarvydas: "[...]I don't see any of them advocating dynamic modification of diagrams.  Why?"
Dan: This is not an argument. Plenty of applications nowadays are dynamic. A program is a network, a program is dynamic so the network should be dynamic. I have mentioned before the example of video games. Have you ever seen a static video game application? Almost all the applications are dynamic.
Maybe you think that "static" means only: the code does not modify or "behavior" relies in code only.
Data is used in programs to implement the links and "links" are "code". Links change the behavior. On the other hand code is data. This is not just philosophy it is exact what it is: code is data and nothing more. Of course we need more "protection" on that part of data (i.e. code) for good reasons.
How data is changing the behavior (network) that usually we associate some code with? By switching one behavior with another behavior; switching function pointers for instance. Is that network modification? Yes, it is. You have changed the connections, you have changed the network, you have changed the behavior. Did it any change to the "code" part? No, but I do not differentiate so abruptly code from data. You modify the network changing data not just code.

Paul Tarvydas: "Did you experience "self modifying code" back in the days of assembler?  Was that a good idea?"
Dan: Yes, it was. It was fun, it created compact and efficient code. It could be dangerous? Yes, it could be. But again, maybe you have in mind that modifying the network only means to modify the code segment. As I have specified earlier you modify the network modifying the connections. Connections could be defined in code or they could be defined in data. "Days of assembler" are not gone. It is the result of any compiler, it does not mean that we, humans, have to program directly in assembler, but we create translators (compilers) able to do that and to optimize the FBP network. Any middleware that moreover is imperative / non-FBP is a real breaker because we need to design a middleware as an impedance adapter. That is bloatware. So, get rid of it.

Dan

unread,
Aug 13, 2012, 10:07:11 AM8/13/12
to flow-based-...@googlegroups.com, co...@mercury.ccil.org
John Cowan: Primarily because an FBP language is a lazy pure functional language, like
Haskell.  Not everyone wants to program in Haskell.
FBP language (if there is any) is not functional. Yes, sometimes lazy but not functional. FBP language is FBP. Components can have state. In FBP you don't use functions using the substitution method. In fact you don't use functions in the first place. Indeed, not everyone wants to program in Haskell.
We have to specify that I understand "functional" as it is defined in programming. A component from FBP could be a mathematical function. This is a longer discussion about what differentiate "functional" in programming from function in mathematics. A function is a function after all but this is another topic.

I do not understand, why you are saying that FBP language is (lazy) pure functional language?
Now let's suppose it is like you say (i.e. FBP is functional). This stops us to go deeper toward the finest granular level? What's the relation? Can you explain?

Dan P.

John Cowan

unread,
Aug 13, 2012, 3:36:32 PM8/13/12
to flow-based-...@googlegroups.com
Dan scripsit:

> FBP language (if there is any) *is not functional*. Yes, sometimes lazy but
> not functional. FBP language is FBP. Components can have state.

*Components* can have state, yes. But the connection language,
mini-language, configuration language, whatever you want to call it,
doesn't have state. Furthermore, it executes its components lazily.
That is why I say that the FBP language is lazy pure functional.

To carry that down into the components seamlessly requires writing them
in a lazy pure functional language too, albeit one with multiple-value
returns corresponding to multiple output ports.

That reminds me that I have been meaning to sketch what a functional-style
connection language syntax might look like. Just for simplicity,
we'll start off with simple components A, B, C with just two ports,
"input" and "output", connected in a simple pipeline. Typical FBP
mini-languages look like this:

connect "input" port of main program to "input" port of component A
connect "output" port of component A to "input" port of component B
connect "output" port of component B to "input" port of component C
connect "output" port of component C to "output" port of main program

But this has no structure, and really can't be understood without a
picture when it gets at all complex. So let's look at a different
approach:

function main(x) = C(B(A(x)))

Here we write A(x) to refer to whatever comes out of the "output" port of x
when its "input" port is connected to whatever x is.

We can easily extend this to multiple input ports by modeling them as
multiple arguments. So if B accepts two inputs, we can write:

function main(x, y) = C(B(A(x), y))

Here x and y are pipeline inputs, and the second input of the main
program is connected to the second input of the B component.

This assumes the input ports are just numbered. But we can name our
input ports by using Python-style keyword syntax:

function main(data=x, control=y) = C(B(data=A(x), control=y))

where both the main program and B have input ports named "data" and
"control".

We can simplify complex graphs by defining local variables:

function main(a, b, c) = {
let a1 = A(a);
let b1 = B(b);
C(a1, b1)
}

And by extending "let" we can deal with multiple named output ports:

function(datain=a, controlin=b) returns (dataout=c) = {
let a1 = A(a);
let out, ctl = B(data=a1, control=b)
D(out, ctl)
}

--
John Cowan co...@ccil.org http://www.ccil.org/~cowan
Most languages are dramatically underdescribed, and at least one is
dramatically overdescribed. Still other languages are simultaneously
overdescribed and underdescribed. Welsh pertains to the third category.
--Alan King

David Barbour

unread,
Aug 13, 2012, 4:51:25 PM8/13/12
to flow-based-...@googlegroups.com
On Mon, Aug 13, 2012 at 12:36 PM, John Cowan <co...@mercury.ccil.org> wrote:
> FBP language (if there is any) *is not functional*. Yes, sometimes lazy but
> not functional. FBP language is FBP. Components can have state.

*Components* can have state, yes.  But the connection language,
mini-language, configuration language, whatever you want to call it,
doesn't have state.

Isolating consideration to the connection language seems a bit odd, like claiming that C is pure because semicolons have no side-effects. 

The relevant concern is whether we can reason about subprograms is if they are pure or stateless, i.e. whether we need to know the history of inputs to understand behavior, whether we can replicate a process (or, conversely, eliminate replicates) without changing their meaning. For FBP, we cannot reason as though subprograms are pure - not even at the "network" layer - because components may be stateful. I.e. state contaminates.

Putting aside internal state, most FBP systems I've seen also allow components some non-encapsulated effects - e.g. interaction with a filesystem. This further hinders reasoning about purity - e.g. we cannot optimize by eliminating FBP subnets (subprograms) just because we don't use certain outputs.

 
Furthermore, it executes its components lazily.

I understand FBP networks as being concurrent, not strict or lazy. 

So, I'd say FBP is concurrent and impure, not lazy and pure.

Regards,

David

John Cowan

unread,
Aug 13, 2012, 5:06:24 PM8/13/12
to flow-based-...@googlegroups.com
David Barbour scripsit:

> Isolating consideration to the connection language seems a bit odd,

I repeat: my point is that the connection language is lazy and pure, not
that the FBP program as a whole is.

> claiming that C is pure because semicolons have no side-effects.

See Conal Elliott's squib "The C Language Is Purely Functional" at
<http://conal.net/blog/posts/the-c-language-is-purely-functional>.
At any rate, if Haskell is pure functional, so is C.

> The relevant concern is whether we can reason about subprograms is if they
> are pure or stateless, i.e. whether we need to know the history of inputs
> to understand behavior, whether we can replicate a process (or, conversely,
> eliminate replicates) without changing their meaning. For FBP, we cannot
> reason as though subprograms are pure - not even at the "network" layer -
> because components may be stateful. I.e. state contaminates.

When I write shell scripts, I don't know and don't need to know whether they
are implemented in a pure or an impure language. State only contaminates
if you can see it.

> Putting aside internal state, most FBP systems I've seen also allow
> components some non-encapsulated effects - e.g. interaction with a
> filesystem. This further hinders reasoning about purity - e.g. we cannot
> optimize by eliminating FBP subnets (subprograms) just because we don't use
> certain outputs.

Well, you're right about that; we can't optimize away "rm" just because it
doesn't have an output.

> Furthermore, it executes its components lazily.
> I understand FBP networks as being concurrent, not strict or lazy.

Concurrent/serial is lazy/strict from a different standpoint.

--
Newbies always ask: John Cowan
"Elements or attributes? http://www.ccil.org/~cowan
Which will serve me best?" co...@ccil.org
Those who know roar like lions;
Wise hackers smile like tigers. --a tanka, or extended haiku

David Barbour

unread,
Aug 13, 2012, 5:44:26 PM8/13/12
to flow-based-...@googlegroups.com
On Mon, Aug 13, 2012 at 2:06 PM, John Cowan <co...@mercury.ccil.org> wrote:
David Barbour scripsit:

> Isolating consideration to the connection language seems a bit odd,

I repeat: my point is that the connection language is lazy and pure, not
that the FBP program as a whole is.

Your point is also pointless and misleading in practice. You should consider not making it, rather than repeating it.
 

> claiming that C is pure because semicolons have no side-effects.

See Conal Elliott's squib "The C Language Is Purely Functional" at
<http://conal.net/blog/posts/the-c-language-is-purely-functional>.
At any rate, if Haskell is pure functional, so is C.

In case you missed it, Conal was making a point of absurdity. Are you trying the same?

Haskell models many excellent impure imperative languages - e.g. IO, ST, State, and various monad transformers built atop them.
 

State only contaminates if you can see it.

Yes. And, in FBP, state is observable.
 

Concurrent/serial is lazy/strict from a different standpoint.

No, it isn't.

Regards,

Dave

Robbert van Dalen

unread,
Aug 14, 2012, 1:45:19 AM8/14/12
to flow-based-...@googlegroups.com

Let consider purely functional FBP from another angle.

Let say we have a FBP system that has:

- The connection (graph) G is an immutable data structure.
- G contains purely functional components and connections between them.
- There is a state S that contains all IPs in flight, which is also an immutable data structure.

We can define a (pure) function - advance - that takes graph G and state S - and returns the a new state S1 (or a new graph G1, in the dynamic case):

(G2,S2)=advance(G1,S1)
(G3,S3)=advance(G2,S2)

I would claim such thing to be purely functional.
Lazy or strict should not make a difference.

Regards,
Robbert.

Ged Byrne

unread,
Aug 14, 2012, 3:22:42 AM8/14/12
to flow-based-...@googlegroups.com
David,

These discussions feel like playing scrabble with somebody who has the only dictionary open in front of him and refuses to let anybody else look at it. 

If terms have a strict definition that resides in a shared vocabulary that we can consult then please let us know where we can find it. 

If you have a clear idea of how you use some terms in your usual context then please recognise that words can have a different usage in other contexts. 

Our discussion on "Pull" is a good example. It's usage in manufacturing is well documented and has nothing to do with lazy evaluation in that context. 

Please say: "That is not how the term is used in my context of...."

Please do not say: "Wrong. You sound really stupid trying to use grown up words you don't understand.  "

It has been recently established that the majority of people here are from a commercial background. Our vocabulary is commercial and not academic. 

Regards,



Ged

David Barbour

unread,
Aug 14, 2012, 3:23:48 AM8/14/12
to flow-based-...@googlegroups.com
On Mon, Aug 13, 2012 at 10:45 PM, Robbert van Dalen <robbert....@gmail.com> wrote:
We can define a (pure) function - advance - that takes graph G and state S - and returns the a new state S1 (or a new graph G1, in the dynamic case):

(G2,S2)=advance(G1,S1)
(G3,S3)=advance(G2,S2)

I would claim such thing to be purely functional.
Lazy or strict should not make a difference.

There are two layers of abstraction here, with different formal properties. You cannot claim that the properties of `advance` are the properties of `G`, especially for those properties related to expression (such as "purely functional"). 

The `advance` expressions are indeed purely functional. But they are, notably, not FBP expressions. As an aside: you'd probably want to extend this with IO types - i.e. (G2,S2,O2) = advance(G1,S1,I1), where `I` is for eventful inputs in that round, and `O` is for eventful outputs. Conversely, you can get rid of S if you have a stateful G, though it is often convenient to have a world-state-type S (e.g. for RESTful IO, or game world rendering). This sort of model has been developed many times in functional programming, cf. conduit, pipe, iteratee.

FBP is presumably described in G, which expresses a stateful system. At the level of describing the graph - aka *programming* FBP - the expressions would *not* be purely functional. One cannot reason about or manipulate subgraphs as though they are purely functional - e.g. cannot freely replicate subgraphs to process multiple input events. Developers must reason about the graph's initial state and how that state will evolve over time state over time in order to reason about correctness of the FBP program you named `G`.

Regards,

David 


On Aug 13, 2012, at 11:44 PM, David Barbour wrote:

>
>
> On Mon, Aug 13, 2012 at 2:06 PM, John Cowan <co...@mercury.ccil.org> wrote:
> David Barbour scripsit:
>
> > Isolating consideration to the connection language seems a bit odd,
>
> I repeat: my point is that the connection language is lazy and pure, not
> that the FBP program as a whole is.
>
> Your point is also pointless and misleading in practice. You should consider not making it, rather than repeating it.
>
>
> > claiming that C is pure because semicolons have no side-effects.
>
> See Conal Elliott's squib "The C Language Is Purely Functional" at
> <http://conal.net/blog/posts/the-c-language-is-purely-functional>.
> At any rate, if Haskell is pure functional, so is C.
>
> In case you missed it, Conal was making a point of absurdity. Are you trying the same?
>
> Haskell models many excellent impure imperative languages - e.g. IO, ST, State, and various monad transformers built atop them.
>
>
> State only contaminates if you can see it.
>
> Yes. And, in FBP, state is observable.
>
>
> Concurrent/serial is lazy/strict from a different standpoint.
>
> No, it isn't.
>
> Regards,
>
> Dave
>
> --
> bringing s-words to a pen fight

David Barbour

unread,
Aug 14, 2012, 4:11:39 AM8/14/12
to flow-based-...@googlegroups.com
On Tue, Aug 14, 2012 at 12:22 AM, Ged Byrne <ged....@gmail.com> wrote:

If terms have a strict definition that resides in a shared vocabulary that we can consult then please let us know where we can find it. 

Push vs. Pull does not have a strict formal definition. The phrases do, however, have rich history in PL and program architectures, and correspondingly deep connotations. (Connotation is a good word for an important kind of informal meaning. I was careful to use it in my earlier discussions with you. Look it up someday.) I cannot educate you in connotations; only you can educate yourself and choose to respect that history and communicate. 


If you have a clear idea of how you use some terms in your usual context then please recognise that words can have a different usage in other contexts. 

It is true that words and word phrases may have different meanings in different contexts. But that does not mean all contexts are equally valid. For example, our discussions on FBP clearly occured in a PL context. As do claims of purity and laziness. If you wish to discuss commercial properties of FBP, then we can use meanings from a commercial context.


Please say: "That is not how the term is used in my context of...."
Please do not say: "Wrong. You sound really stupid trying to use grown up words you don't understand.  "

Nice straw man characterization on that latter point.

If I recognize that my correspondent is accidentally using a term out of context, I will politely make a note of it. 

You used phrases like "To clarify this is *my* definition of pull and push." (emphasis mine). To me, this felt like yet another chapter of Humpty Dumpty (There's glory for you!) Saying it was your definition did not give the impression that you were accidentally using a word out of context; rather, my impression was that you were blatantly disrespecting the word's history and meaning in order to substitute your pet meaning. Since the topic itself was push vs. pull relating to earlier discussion of the subject, it even seemed like intentional equivocation (a form of sophistry). Despite that impression, I remained as polite as I could manage.

The current topic is not subject to a simple misunderstanding of definitions. It seems more like confusing layers of abstraction - i.e. the fallacy that "X can be implemented with Y therefore X has the properties of Y". In this case: "A subset of FBP can be implemented with pure functions, therefore that subset of FBP is purely functional." This certainly sounds more clever than: "A subset of chess can be implemented with C++, therefore that subset of chess has properties of C++." But both sentences are equally fallacious. 

Related: Ceci n'est pas une pipe.

Regards,

Dave

Brad Cox

unread,
Aug 14, 2012, 8:58:07 AM8/14/12
to flow-based-...@googlegroups.com
Arrogance doesn't have a strict definition either, but we sure know it when it happens.

On Tue, Aug 14, 2012 at 4:11 AM, David Barbour <dmba...@gmail.com> wrote:
On Tue, Aug 14, 2012 at 12:22 AM, Ged Byrne <ged....@gmail.com> wrote:
If terms have a strict definition that resides in a shared vocabulary that we can consult then please let us know where we can find it. 

Push vs. Pull does not have a strict formal definition. The phrases do, however, have rich history in PL and program architectures, and correspondingly deep connotations. (Connotation is a good word for an important kind of informal meaning. I was careful to use it in my earlier discussions with you. Look it up someday.) I cannot educate you in connotations; only you can educate yourself and choose to respect that history and communicate. 

Yet more omitted. 

Paul Tarvydas

unread,
Aug 14, 2012, 9:33:24 AM8/14/12
to flow-based-...@googlegroups.com
On 12-08-14 08:58 AM, Brad Cox wrote:
> Arrogance doesn't have a strict definition either, but we sure know it
> when it happens.

Seconded.

Paul Morrison

unread,
Aug 14, 2012, 9:42:26 AM8/14/12
to flow-based-...@googlegroups.com
On 11/08/2012 2:42 PM, David Barbour wrote:

Parenthetically, my JavaFBP VolumeTest executes 100,000,000 sends and 100,000,000 receives in 4 mins. on my 4-processor desktop, and keeps all processors 99% busy!

That seems quite poor for performance, even in Java. I.e. you're breaking it down to 420k IPs per second, even after buffering. Granted, I don't know the quality of your processors, the nature of the benchmark, or the size of your bounded buffers. But Erlang, Akka, AsyncFP, etc. tend to benchmark in millions of messages per second. 


The above benchmark involves pumping 100,000 IPs through 1,000 Copy processes in a "string of pearls" configuration.  I ran another benchmark where I generate 100,000,000 IPs and simply send them to a Discard process - this took 20 mins. <blush>.  Now, if my calculations are correct, this means that a send/receive pair takes 2.39 microsecs, but a create/drop pair takes 9.6 microsecs. - this seems a bit high, as create is just a Java "new" - and drop isn't any code at all (presumably, when the IP is no longer referenced, GC takes over...?). 

My machine contains 4 AMD Phenom II 925 processors, rated at 2.8 GHz - don't know how many mips that is... And I'm running with a connection size of 10 IPs.

My question - and I've never done any Java profiling - is a) are these numbers "reasonable", b) if not, how do I get a better handle on what's going on? :-)  And c) is it meaningful to compare JavaFBP with Erlang, Akka, etc.?

TIA

Paul M.

Paul Tarvydas

unread,
Aug 14, 2012, 9:51:03 AM8/14/12
to flow-based-...@googlegroups.com
On 12-08-13 09:37 AM, Dan wrote:

> Paul Tarvydas: "Did you experience "self modifying code" back in the days of assembler?  Was that a good idea?"
Dan: Yes, it was. It was fun, it created compact and efficient code. It could be dangerous? Yes, it could be. But again,

In my view, the point of a diagram is to communicate design intention to other humans.  Same with textual source code.  The computer doesn't ultimately care that you've used ASCII and the syntax of Java, only other human architects / engineers / maintainers care.

The problem with self-modifying ASCII code was that maintainers found it hard to follow what was going on.

A diagram that modifies itself during runtime, likewise, is useless from the perspective of maintenance.

When you build "dynamic" systems, e.g. games, say in Java, do you write self-modifying code?  (That could actually be done - one could dynamically generate .class assembler files).

Why would the rules be different when using a different syntax, say instead of ASCII, a syntax made up of lines and boxes?


Similarly, I have found that "a + b" expresses the addition of two variables more succinctly than a box with two inputs, one output and a cross drawn in its title bar.  On top of which, everyone who's graduated from grade 3 already understands this notation.

FBP expresses architectural intent that cannot be expressed well in text, and text expressions (etc.) express intent that isn't any more clear when drawn out.  There's a place for both.

pt

John Cowan

unread,
Aug 14, 2012, 10:24:54 AM8/14/12
to flow-based-...@googlegroups.com
Paul Tarvydas scripsit:

> FBP expresses architectural intent that cannot be expressed well in
> text,

Actually, I think it can be: see my previous posting.

--
If you understand, John Cowan
things are just as they are; http://www.ccil.org/~cowan
if you do not understand, co...@ccil.org
things are just as they are.

David Barbour

unread,
Aug 14, 2012, 11:29:39 AM8/14/12
to flow-based-...@googlegroups.com
On Tue, Aug 14, 2012 at 5:58 AM, Brad Cox <brad...@gmail.com> wrote:
Arrogance doesn't have a strict definition either, but we sure know it when it happens.

True enough. Even I recognize the arrogance in my tone. 

Paul Tarvydas

unread,
Aug 14, 2012, 11:50:34 AM8/14/12
to flow-based-...@googlegroups.com
On 12-08-14 10:24 AM, John Cowan wrote:
> Paul Tarvydas scripsit:
>
>> FBP expresses architectural intent that cannot be expressed well in
>> text,
> Actually, I think it can be: see my previous posting.
>
I agree that your idea is the most reasonable text representation I've
seen. I may try it out on my next iteration (even if I continue to like
diagrams better, I will need an intermediate representation).

I'm used to using components with many ports, e.g. see "AuxFunctions"
under Hierarchical Schematics at http://visualframeworksinc.com/ (from a
smart meter project in the UK).

Fisk's "full metal jacket" might be relevant:

http://web.onetel.com/~hibou/Full%20Metal%20Jacket.html

pt

David Barbour

unread,
Aug 14, 2012, 12:10:00 PM8/14/12
to flow-based-...@googlegroups.com
You had 99% utilization in your earlier benchmark - i.e. the OS never entered idle mode for any processor, always had something to do. You did not mention utilization on the recent benchmark, but my hypothesis is that it is about 25% because you only have two processes and too small a buffer to keep two processors busy - so it will mostly be a context-switching fest. It should not surprise that it throughput is down by a factor of four. (2.39 * 4 = 9.6)

Also, you're measuring throughput, much of which will be dominated by context switching and GC, not latency or handoff times. You'll need to adjust your benchmarks (or create new ones) to measure these different properties. To give you an idea: token-ring networks are a decent for many metrics, and by adjusting the number of tokens in transit and the number of "rounds" you can measure many different properties.

Regards,

Dave

Raoul Duke

unread,
Aug 14, 2012, 1:06:13 PM8/14/12
to flow-based-...@googlegroups.com
hi,

David might come across as, and even be, arrogant, but on the whole I
have never seen him actually be rude or mean like you might see all
over the place on the Internet, and his comments are more often than
not very good food for thought. $0.02.

sincerely.

Paul Morrison

unread,
Aug 14, 2012, 1:11:52 PM8/14/12
to flow-based-...@googlegroups.com
Thanks, Dave,

That makes perfect sense! I'll give that idea a try when I get home tonight. By "token ring" I assume you mean a loop-type topology - and I will pay attention to the CPU utilization!

Paul

Sent from Samsung Galaxy Tab (tm) on Rogers

Dan

unread,
Aug 14, 2012, 1:19:10 PM8/14/12
to flow-based-...@googlegroups.com
Paul T: "The problem with self-modifying ASCII code was that maintainers found it hard to follow what was going on."
Allowing self-modifying ASCII code without keeping the (original) source would be a nightmare. I was not having this in mind.

Paul T: "A diagram that modifies itself during runtime, likewise, is useless from the perspective of maintenance."
Strongly disagree on this one. I have said that the diagram modifies itself in two ways:
  1. modifying the code at runtime (rarely used or not at all)
  2. modifying the links (connections, pointers to functions/methods/objects)
Most of the applications are changing the diagram by changing data not code. But the data they change means to change the diagram that it is like changing the code. Reconfiguring by changing data is like changing the code at runtime. The term "(re)configuring" itself means coding. I repeat: I do not differentiate so abruptly code from data. Code is data and data could be code. Changing a connection by changing a pointer means changing the diagram. It means to change behavior, to change code. But this "code" is not in the "code segment" meaning it is not data interpreted by the microprocessor as code as it is: ADD or MUL.
Changing the diagram it does not mean I am losing the original (before modification). The original diagram is a value at time t1 that will be preserved for various purposes.

I do agree that not all programs change the diagram because there are programs that just process the input from an external device and and spit the output to an external device. The video game application example is good because in that case we have a simulation of a world that modifies itself, where state and behavior are important. It is not just a part of a world that stays unmodified like a machine that processes some object from a conveyor belt.
Conclusion: the diagram can modify without changing the "code" but it is like changing the code because the diagram is the code but also the state.

Paul T: "When you build "dynamic" systems, e.g. games, say in Java, do you write self-modifying code?  (That could actually be done - one could dynamically generate .class assembler files)."

As I said before rarely I do change the code at runtime but in almost all the cases I do change the diagram. There is no doubt about it. If I do not change the diagram then what changes? We are talking about a world that change itself not about a part of it (e.g. a machine) that remains the same. The entire world (simulated in the game) is a program: code+data. The diagram changes.

Paul T: "Why would the rules be different when using a different syntax, say instead of ASCII, a syntax made up of lines and boxes?"
Yes, they don't need to be different.

Paul T: "Similarly, I have found that "a + b" expresses the addition of two variables more succinctly than a box with two inputs, one output and a cross drawn in its title bar."
Of course. The diagram (graphic) version of a+b is an overload. They should be equivalent.

Regards,
Dan P.

David Barbour

unread,
Aug 14, 2012, 1:27:18 PM8/14/12
to flow-based-...@googlegroups.com
Don't forget to try the degenerate case of a loop: just one process. This gives you some useful information about minimum handoff times and internal overheads.

Regards,

Dave

Dan

unread,
Aug 14, 2012, 1:36:08 PM8/14/12
to flow-based-...@googlegroups.com
It seems it is very hard for almost all the programmers here interested in FBP to translate from a pure declarative FBP language (data flow driven) to an imperative language like the assembler (control flow driven).

In the end it is the only way and there is a form of equivalence. But if you mix and interpose other languages as middleware between a hypothetical FBP declarative language and assembler then everything becomes bloated.

I would be very interested to discuss the translation process from a simple FBP program (diagram) to a simple ASM program. The process itself (compilation) is an FBP program. The binary code is data that flows from memory into the microprocessor and back to the memory. Everything is data flow based in the end but it is hard to find the common picture and the transformation from one state (FBP declarative source code, text or diagram) into the other state/form of existence (binary code).

In fact we have to replace all the components from the diagram with data in the memory. Part of this is data as we know it (floats, ints etc.) some other part is data as opcodes. The links/connections are represented also as data but also as opcodes. The result is a representation of the FBP diagram but it is not one-to-one representation because the compiled code could depend on the number of processors and the diagram is "stretched" into a single thread control flow based.

If this is a subject of interest I will create a new topic.

Dan

Raoul Duke

unread,
Aug 14, 2012, 2:03:11 PM8/14/12
to flow-based-...@googlegroups.com
On Tue, Aug 14, 2012 at 10:36 AM, Dan <dpol...@gmail.com> wrote:
> I would be very interested to discuss the translation process from a simple
> FBP program (diagram) to a simple ASM program.

ugh.

obviously everybody is allowed ;-) to talk about whatever they want
to, but i'd rather be a gad-fly on the wall of a discussion about how
to do FBP/declarative on top of something like JActor. :-) i guess i'm
an anti-assembly bigot?

sincerely.

David Barbour

unread,
Aug 14, 2012, 2:19:54 PM8/14/12
to flow-based-...@googlegroups.com
On Tue, Aug 14, 2012 at 6:51 AM, Paul Tarvydas <paul.t...@rogers.com> wrote:
In my view, the point of a diagram is to communicate design intention to other humans.

We write code to communicate with both other humans and our computers. Which audience is the more tyrannical and exacting? 

Hypothesis: If the only point was to communicate design intentions to other humans, our code would be very different.
 

The problem with self-modifying ASCII code was that maintainers found it hard to follow what was going on. A diagram that modifies itself during runtime, likewise, is useless from the perspective of maintenance.

I think you generalize prematurely. 

Have you not considered that the trouble with maintaining self-modifying ASCII might be related to the structure (or lack thereof, with ASCII) rather than the self-modification? Programmers often work effectively with self-modifying structures - and they reason about these systems in terms of structural constraints such as modularity, confinement, connectivity.
 

Why would the rules be different when using a different syntax, say instead of ASCII, a syntax made up of lines and boxes?

Why wouldn't they be different? 

Consider, for a few minutes, how typed and structured editing would impact a self-modifying computer. 

Regards,

Dave

Paul Morrison

unread,
Aug 14, 2012, 2:53:06 PM8/14/12
to flow-based-...@googlegroups.com
That's confusing! How is a one-process loop different from a regular Java program? Unless you are saying this is test for the minimal send/receive pair, with no possibility of suspension?

Also, is a handoff the same as a context switch?

TIA

Paul

David Barbour <dmba...@gmail.com> wrote:

David Barbour

unread,
Aug 14, 2012, 3:51:34 PM8/14/12
to flow-based-...@googlegroups.com
On Tue, Aug 14, 2012 at 11:53 AM, Paul Morrison <paul.m...@rogers.com> wrote:
That's confusing!  How is a one-process loop different from a regular Java program?  Unless you are saying this is test for the minimal send/receive pair, with no possibility of suspension?

The test would indeed be for the minimal send/receive pair with no possibility of suspension.
 

Also, is a handoff the same as a context switch?

By "handoff" I mean a minimal send/receive pair, not including OS-level context switches or latency waiting in buffers and so on. (In general, buffering is a tradeoff that improves througput and efficiency (due to memory locality) but at a cost to latency.)

Regards,

Dave

Paul Morrison

unread,
Aug 14, 2012, 10:15:17 PM8/14/12
to flow-based-...@googlegroups.com


On Tuesday, August 14, 2012 11:50:34 AM UTC-4, paul.tarvydas wrote:

I agree that your idea is the most reasonable text representation I've
seen.  I may try it out on my next iteration (even if I continue to like
diagrams better, I will need an intermediate representation).


Granted that I couldn't find the representation you are referring to, but what about Wayne Steven's notation? ProcessA(CompA) OUT -> IN ProcessB OUT -> ProcessC, etc.... Or did you want to capture x-y coordinates?  Perhaps they could be specified out of line, so they don't affect the readability of the text...

John Cowan

unread,
Aug 14, 2012, 10:32:42 PM8/14/12
to flow-based-...@googlegroups.com
Paul Morrison scripsit:

> Granted that I couldn't find the representation you are referring to,

See https://groups.google.com/d/msg/flow-based-programming/ZekHphET9_w/rgO5ZhQZfwUJ

--
They tried to pierce your heart John Cowan
with a Morgul-knife that remains in the http://www.ccil.org/~cowan
wound. If they had succeeded, you would
become a wraith under the domination of the Dark Lord. --Gandalf

Paul Morrison

unread,
Aug 15, 2012, 10:14:42 AM8/15/12
to flow-based-...@googlegroups.com
On 14/08/2012 10:32 PM, John Cowan wrote:
> Paul Morrison scripsit:
>
>> Granted that I couldn't find the representation you are referring to,
> See https://groups.google.com/d/msg/flow-based-programming/ZekHphET9_w/rgO5ZhQZfwUJ
>
Thanks, John, that's neat! Does it support loop topologies - I would
think it does!

Paul

Paul Morrison

unread,
Aug 15, 2012, 4:12:00 PM8/15/12
to flow-based-...@googlegroups.com
Hi Dave,

Haven't done the single process test yet - but I added 3 Copy processes to my second VolumeTest, and then got close to 100% utilization of the 4 processes (strangely, 4 processes only gave me about 75% utilization).  The elapsed time (processing 25,000,000 IPs through 5 processes) went down to something much more sensible (4 mins. 44 secs - still too high?)  , giving me 1.77 microsecs per create/drop pair, and approx. 2.40 microsecs per send/receive pair.  Thanks for your help!

Paul
It is loading more messages.
0 new messages