Concurrency support?

Lars T Hansen lth at opera.com
Mon Jun 26 01:09:06 PDT 2006


Nicolas Cannasse writes:
 > >>FWIW, concurrency support (or more specifically, the ability to  
 > >>yield while waiting for an event) is easily the top item in my list  
 > >>of enhancement requests for the JavaScript language.  I've been  
 > >>building large-ish client-side "AJAX" applications for several  
 > >>years now, and I find it painfully difficult to debug asynchronous  
 > >>callbacks and read asynchronous code.  My wife, in particular,  
 > >>would like to see concurrency in JavaScript so that she might have  
 > >>normal conversations with me the end of my workday.
 > > 
 > > 
 > > See http://developer.mozilla.org/es4/proposals/ 
 > > iterators_and_generators.html, apologies for the gaps there.  They  
 > > will be filled in shortly.
 > > 
 > > The idea in emulating Python 2.5 generators is that you can coroutine  
 > > your code -- you can use a standard Ajax library to map a single  
 > > function that contains yield expressions across a series of  
 > > asynchronous callbacks, without having to break that function up into  
 > > a bunch of callback functions.
 > > 
 > > /be
 > 
 > What about full continuations support à la call/cc ? Generators are just
 > a specific application of continuations, which are much more powerful
 > when freely usable.

Full continuations interact in surprising ways with side effects.
Slipping into Scheme for a moment, the issue is exemplified by this
implementation of the map function:

    (define (map f xs)
      (let loop ((acc '()) (xs xs))
        (if (null? xs)
            (reverse! acc)
            (loop (cons (f (car xs)) acc) (cdr xs)))))

Suppose f captures it continuation and that code outside the call to
map invokes that continuation later.  Then the result returned from
the first call to map will be observably changed by this invocation:

  # (map (lambda (x) (+ x 1)) (list 1 2 3))
  (2 3 4)
  # (define (fn x) 
      (if (= x 2) 
          (set! c (call-with-current-continuation 
                    (lambda (k) k))))
      (+ x 1))
  # (define v (map fn (list 1 2 3)))
  # v
  (2 3 4)
  # (c 4)
  # v
  (4 3 2 3 4)

This is surprising in the sense that this is not really the behavior
you expect from map, and indeed an implementation of map that does not
share structure between its intermediate data and returned data
behaves more as expected.  It just needs to be constructed more
carefully, and will cons twice as much (or use O(n) stack).

It's not obvious that this has huge implications for the standard
libraries in ECMAScript as they stand, but this type of problem will
tend to make libraries more brittle in general.

The point I want to make is that we probably do not want to provide
full continuations as an abstraction on which to build threads,
coroutines, generators, exceptions, and so on, but instead to provide
these other more controllable forms directly instead.

--lars




More information about the Es4-discuss mailing list