clj-commons / manifold

A compatibility layer for event-driven abstractions
1.02k stars 106 forks source link

let-flow with multiple derefs #140

Closed neverfox closed 3 years ago

neverfox commented 7 years ago

Is it the intended behavior of let-flow that explicit derefs in the bindings preclude the automatic realization of deferreds? For example:

(require '[manifold.deferred :as md])
(require '[cats.monad.either :as eth])

(def result (md/future (eth/right 1)))

@(md/let-flow [v @result]
   v)

Here I expect to get 1, since cats' Right is deref-able, and instead I get #<Right 1>, meaning the @ only took me as far as realizing the future. To get at the value, I have to do this:

@(md/let-flow [v @@result]
   v)

or

@(md/let-flow [r result
               v @r]
   v)

The first feels like it defeats one of the major reasons for using let-flow and the second is just gnarly, imo. Thoughts?

danielcompton commented 7 years ago

The second one makes sense to me. If your future returns a derefable value then it makes sense you still need to deref it?

ztellman commented 7 years ago

Manifold will automatically dereference whatever it can coerce into a deferred, which by default are Java futures, and objects which implement both clojure.lang.IPending and clojure.lang.IDeref. This is necessary because most Clojure deref objects will block, and so to emulate the on-realized behavior we need to deref it on a separate thread. You can also extend the manifold.deferred.Deferrable protocol over any class you like. It seems like this last approach is most appropriate, based on my imperfect understanding of what Right represents.

KingMob commented 3 years ago

This seems to be resolved in the comments, so I'm closing it.