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