Share your thoughts in the 2021 Clojure Community Survey!

Welcome! Please see the About page for a little more info on how this works.

+3 votes
in Refs, agents, atoms by
retagged by

If a delay is currently processing, calling realized? causes the caller to block until the delay has completed and then returns true.

The behaviour I would have expected is that it should return false, which is what happens with futures. After all, if you wanted to wait until it was completed, you would deref it.

(also there don't seem to be any tags or categories related to concurrent programming, but since delay is part of clojure.core, I assume this is the correct place to ask)

2 Answers

0 votes

In the meantime you can extend clojure.lang.Delay to my.Delay and override isRealized to not be synchronized, and have a new delay:

(defmacro my-delay [& body]
  (list 'new 'my.Delay (list* `^{:once true} fn* [] body)))
I think since `realized?` and `force` are no longer synchronized, the concurrency primitive service that delay provides has changed.  Now multiple callers from multiple threads can potentially `force` the delay simultaneously if the work is not yet done, meaning the thunk may be called multiple times before being cached.
Removing synchronized on isRealized() does not change the deref code or its semantics across threads (which are still synchronized in deref()).

Because fn is volatile, publication of this value is safe and will be seen across threads.
0 votes
Thanks for getting onto this so quickly Alex.

Yesterday I also noticed that just trying to print the value of executing delay in the REPL without derefing it will also block. However, I'm 99% sure that's just because whatever is building the string representation is also calling "realized?" so I don't think that's a different bug.