On Wed, Dec 2, 2009 at 1:49 PM, Colin Putney <span dir="ltr">&lt;<a href="mailto:cputney@wiresong.ca">cputney@wiresong.ca</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

<div class="im"><br>
On 2-Dec-09, at 8:26 AM, Nicolas Cellier wrote:<br><br></div><div class="im">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Especially pipelines are quite tricky with a forked process... I got<br>
to rest a bit and think.<br>
This kind of implementation natively has good parallelism properties,<br>
unfortunately this won&#39;t exploit multi-core/processors any time soon<br>
in Smalltalk...<br>
</blockquote>
<br></div>
I&#39;m guessing you mean running each stage of the stream in a separate Smalltalk Process, using the Pipes and Filters pattern?<br>
Stephen Pair did some neat stuff with that a few years ago. It&#39;s indeed tricky. I wonder if it&#39;s worth it in this case, though, exactly because Smalltalk doesn&#39;t exploit multiprocessors. Flow of control inside a stream might be complicated without parallelism, but it&#39;s probably easier to debug.</blockquote>

</div><div><br></div><div>Some time ago I implemented dynamic bindings, which gives you an ability to get and set process local (or more accurately, stack local) variables.  I had also implemented a SharedStream class that firmed up the semantics of underflow vs end of stream as well as overflow (if you wanted to cap the size of the buffer).  It was process safe (as the name implies) and had blocking and non blocking protocols.  It could handle any kind of object and was efficient for bytes and characters.</div>

<div><br></div><div>I later read a paper on a more expressive model for concurrency (can&#39;t recall the author) that discussed conjunctive and disjunctive joints and I created an implementation.  With the protocol I chose, you could do something like:</div>

<div><br></div><div>   ([a doSomething] | [b doSomething]) value</div><div><br></div><div>That would evaluate both blocks concurrently and answer the first one to complete (and terminate the laggard).  The stack is stitched together in such a way that an exception signaled in either block would propagate out and could be handled naturally with an on:do:...when in a handler, both of the child processes would be suspended.  This was the disjunctive joint.  Similarly, you could do:</div>

<div><br></div><div>   ([a doSomething] &amp; [b doSomething]) value</div><div><br></div><div>This would evaluate both blocks concurrently, but not return an answer until both completed (and it would return the answer of the last block).  It has the same exception handling semantics.  This was the conjunctive joint.  You could also chain as many blocks as you wanted to run them concurrently.</div>

<div><br></div><div>From there it was a natural extension want to do something like:</div><div><br></div><div>   (someString &gt;&gt; [x grep: &#39;foo&#39;] &gt;&gt; [x sort]) value</div><div><br></div><div>Where &gt;&gt; represented a pipe (in the unix sense) and used SharedStream and the concurrency work to connect up the processes.  I used dynamic bindings to define stdin and stdout for each of the processes.  With some contortions I managed to reduce it to something like:</div>

<div><br></div><div>   (someString &gt;&gt; (Grep with: &#39;foo&#39;) &gt;&gt; Sort) value.</div><div><br></div><div>I imagine with implicit self sends (ala Self or Newspeak), it could be reduced even further:</div><div>

<br></div><div>   (someString &gt;&gt; grep: &#39;foo&#39; &gt;&gt; sort) value</div><div><br></div><div>- Stephen</div>