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]

Re: proposed support for lazy values


On Jun 3, 2011, at 3:33 PM, Per Bothner wrote:

I'm working on modifying the handling of "lazy" values.
The main change is that I'm adding "implicit forcing",
as allowed by R5RS (and the R7RS draft).

The classes that implement (delay EXP) and (future EXP) are modified
to implement a new gnu.mapping.Lazy interface:

public interface Lazy<T>
{
   public T force() throws Throwable;
}

I plan to add a new type descriptor to indicate lazy values:
 lazy[T]
will be equivalent to the Java type gnu.mapping.Lazy<T>.
(See the previous message about parameterized types.)

Given a type T which is neither Object, nor a lazy type, then
Kawa will support bi-directional conversion between type T and lazy[T].
In a context that requires T, if we have a lazy value, Kawa will
automatically call force. This includes arithmetic operations.


Accessing a truth value (as in the condition of an 'if') also does a force.
(This will cause a slight performance hit if the type of the
condition expression is unknown, since in that case the compiler has to add a
run-time check for lazy values, rather than just comparing against #f.)


I'm suggesting that a lazy value would not be an instance of a non- lazy type.
I.e.
(instance? 3 integer) ==> #t
(instance? (delay 3) integer) ==> #f
OTOH, perhaps:
(instance? 3 lazy[integer]) ==> #t
(instance? (delay 3) lazy[integer]) ==> #f
One reason is to try to keep laziness as a feature you only pay for
only when you use it (at least as much as possible). Also I think it makes
sense to consider type T as being "more specific" than lazy[T].


Converting a value v to lazy[T] where v is compatible with T is
trivial: Just create a pre-evaluated Promise object whose value is v.

The display function will automatically call force - but write will not.
Note the Kawa's REPL by default displays the result.


One use case is to support lazy and parallel arrays, though
that will also be a work-in-progress. The plan is that a command window
will include "more"-style functionality (such as I implemented for Emacs's
term-mode), so if the REPL evaluates to a lazy infinite sequence only
as much will be evaluated and printed as requested by the user.


Comments? Obviously this is going to be somewhat experimental!

So the mechanism for creating an object of type lazy[T] would be to call
(delay EXP), where EXP is an expression that would evaluate to an instance
of T?


So for instance:
(define the-answer ::lazy[integer] (delay (* 2 3 7)))
;;; Right now, the multiplication hasn't happened yet
(+ the-answer 0) ;; <- implicit force here as context requires an integer



By the way, I notice that force() in kawa.lang.Promise checks result==null
twice, presumably as a lockless mechanism to make sure the result is only
memoized once in case two threads both force it simultaneously. It seems like
this could still lead to trouble, if the promised computation has side effects.
Even though the result seen by all threads will be the same (usually, though I
think you'd need an AtomicReference and compareAndSet in there to be absolutely
sure), there's still nothing preventing the promise from being evaluated N
times:


#|kawa:14|# (define my-promise (delay (begin (display "Ding!") (newline))))
#|kawa:15|# (do ((i 0 (+ i 1))) ((= i 10)) ((java.lang.Thread (runnable (lambda () (force my-promise)))):start))
Ding!
Ding!
Ding!
Ding!
Ding!
Ding!



That may be an acceptable trade-off to avoid using a synchronized block, but it seems
like something that should be documented.



-- Jamison Hope The PTR Group www.theptrgroup.com




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