proposed support for lazy values

Jamison Hope jrh@theptrgroup.com
Fri Jun 3 22:25:00 GMT 2011


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





More information about the Kawa mailing list