Block temps was: Porting from other dialects

Patrick Logan patrickl at servio.gemstone.com
Tue Aug 18 22:39:00 UTC 1998


  The issue is not nilling out the block temporary. The issue is
  having one slot per block-activation so that blocks may be value'd
  re-entrantly...

  This show that even block parameters have the problem. As Glenn
  pointed out earlier, parameters are conceptually the same as
  temporaries...

(1) It would be nice to implement closures without mucking with byte
    codes, the interpreter, etc. 

(2) Closures are an awful lot like objects. (Referring back to Steele
    and Sussman's work in the 1970s.)

So I wonder if a halfway decent approach to providing closures might
be a source-to-source transformation?

================================================================

For example the code previously posted...

  | output supposedlyReentrantBlock guard |
  output := WriteStream on: String new. "I'm used to String new writeStream..."
  guard := SharedQueue new.   "Used for process synchronization"
  supposedlyReentrantBlock := 
    [ :array  |  
     1 to: array size do: 
       [ :index | 
        output print: (array at: index); space. Processor yield. ].
     guard nextPut: nil.   "  signal the guard  "
    ].
  [supposedlyReentrantBlock value: #(1 2 3) ] fork.
  [supposedlyReentrantBlock value: #(-1 -2 -3) ] fork.
  guard next; next.  "  wait for two guard signalings  "
  ^output contents 

....could be compiled, following a closure analysis and rewriting,
   as (the rewritten source is not saved, it is implicit)...

  | output guard 
    supposedlyReentrantBlockOne supposedlyReentrantBlockTwo |
  output := WriteStream on: String new. "I'm used to String new writeStream..."
  guard := SharedQueue new.   "Used for process synchronization"
  [supposedlyReentrantBlockOne := ClassForSupposedlyReentrantBlock new.
   supposedlyReentrantBlockOne 
     array: #(1 2 3) 
     guard: guard
     output: output] fork.
  [supposedlyReentrantBlockTwo := ClassForSupposedlyReentrantBlock new.
   supposedlyReentrantBlockTwo 
     array: #(-1 -2 -3) 
     guard: guard 
     output: output] fork.
  guard next; next.  "  wait for two guard signalings  "
  ^output contents

....where...

ClassForSupposedlyReentrantBlock>>array: array guard: guard output: output

  1 to: array size do: 
    [ :index | 
     output print: (array at: index); space. Processor yield.].
  guard nextPut: nil.   "  signal the guard  "

================================================================

Blocks that do not capture any lexical variables compile as Blocks do
already. Blocks that *do* capture lexical variables are rewritten as
classes that follow the Block protocol with instance variables for the
lexical variables they capture.

I am sure there are holes yet to be shot into this one minute
analysis, but it is a thought. For example, #fork would have to do the
right thing. And it isn't appealing to add a class to the system for
every closure. (You don't want to see them necessarily, and you want
the system to get rid of them automatically when they are no longer
needed.)

-- 
Patrick Logan                 mailto:patrickl at gemstone.com
Voice 503-533-3365            Fax   503-629-8556
Gemstone Systems, Inc         http://www.gemstone.com





More information about the Squeak-dev mailing list