{ Futures


R.H. Halstead, jr. Multilisp: a language for concurrent symbolic computation, ACM Transactions on Programming Languages and Systems, Vol. 7, No. 4, October 1985, Pages 501-538.

This is a simple implementation of futures in JScheme. The construct (future X) immediately returns a future for the value of the expression X, and concurrently begins evaluating X in a separate thread. A future is initially undetermined. It becomes determined when its value has been computed. Use (touch f) to determine the value of a future, f. touch will suspend until the future is determined.

One issue is how to handle exceptions. In this version, a future becomes determined either by producing a value, or throwing an exception. A future catches any exception and rethrows it when it is touched.

Procedure names that begin with "%" are private.

(define-macro (future exp) `(%make-future (lambda () ,exp)))

(define (determined? f)
  ;; Is future f determined?
  (not (%future-thread f)))
(define (future? f)
  ;; Is Object f a future?
  (and (vector? f) (eq? (vector-ref f 0) 'future)))

(define (touch f)
  ;; If the future has a thread, it means it is not done.
  ;; Use join() to wait for it to be done before fetching the value.
  (let ((thread (%future-thread f)))
    (if thread (.join thread))
    (if (%future-exception f) (throw (%future-exception f))
	(%future-value f))))

;;; `#(future ,thread ,value ,exception)
(define (%allocate-future)(vector 'future #f #f #f))
(define (%future-thread f) (vector-ref f 1))
(define (%future-value f) (vector-ref f 2))
(define (%future-exception f) (vector-ref f 3))

(define (%future-result-set! f v e)
  (synchronize f (lambda (f)
		   (vector-set! f 3 e)
		   (vector-set! f 2 v)
		   (vector-set! f 1 #f))))

(define (%make-future thunk)
  (let* ((fu (%allocate-future))
	 (thread (Thread.
		  (lambda ()
		       (%future-result-set! fu (thunk) #f)
		     (lambda (e)
		       (%future-result-set! fu #f e)))))))
    (vector-set! fu 1 thread)
    (.start thread)