This is the mail archive of the kawa@sourceware.org mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

auto-forced lazy values for Kawa


Attached is an experimental patch to Kawa to better support
a lazy evaluation style, including multi-threaded futures.

We already have:
  (future EXP) - Evaluate EXP in a new thread.  Return a "future"
     object, which is a wrapper for the *eventual* result of EXP.
  (delay EXP) - Return a promise for the value of EXP.
  (force LAZY) - Where LAZY is the result of future or delay.
     Waits until EXP is evaluated and returns the value.

delay and force enable "lazy evaluation" and future enables a
convenient way to evaluate using multiple threads.  But having
to sprinkle force all over the code makes for ugly code.

The patch implements "auto-forcing" - force is called automatically
"when needed", which roughly means when the specific value is needed
for a core operations, like arithmetic or comparisons.

Here is a runnable example:

(define (squares start end)
  (if (= start end) '()
      (cons (* start start)
            (future (begin (sleep 1) (squares (+ start 1) end))))))

(define (print-list l) ::void
  (cond ((eqv? l '()))
        (else
         (display (car l))
         (newline)
         (print-list (cdr l)))))

Combining auto-forcing with type-declarations raises the question
how those interact:  Should the type "integer" be an immediate
(already-forced) gnu.math.IntNum, or should it be a value that
evaluates to an IntNum *after forcing*?  A type declaration in
a pure functional language like Haskell chooses the latter:
An "integer" value is one that when forced is an integer.
However, for a hybrid language like Kawa it seems better to
make "integer" mean an immediate forced IntNum:

integer - an immediate gnu.math.IntNum value
lazy[integer] - a value that evaluates to an IntNum.
  Maps to the Java type gnu.mapping.Lazy<gnu.math.IntNum>.

This way of doing it provides (I think) better control and
less surprise to programmers.  More importantly (for Kawa)
is it makes it easier to write high-performance code with
less overhead: Auto-forcing happens during type-conversion,
and not on each operation, as long as we have the necessary
type information.  For example:

  (define (square i::integer) (* i i))
  (define x::object 4)
  (square x) ;; implicit force
  (define y::integer 5)
  (square y) ;; no force needed

In this example there is no forcing code in the square method,
and no forcing needed if a known-non-lazy value is passed to
a known function with a non-lazy parameter.

(It would probably be feasible to invert the convention,
so that you have a type integer that eventually evaluates
to an IntNum and a type eager[integer] that is forced.
However, that seems more difficult and is incompatible
with existing code.)

eq? is low-level and does not do auto-forcing
eqv? equal? = do auto-forcing
instanceof tests are TDB - currently does not do auto-forcing.
display does auto-forcing; write does not.

Please try it out and let me know what you think.
I'm sure there are bugs, most likely places where force is missing.
--
	--Per Bothner
per@bothner.com   http://per.bothner.com/

Attachment: lazy.patch
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]