Closed cosineblast closed 1 year ago
What's the use case you had in mind?
let-flow
's value is in handling dependencies between deferred's automatically, but both if-let
and when-let
take only a single binding, so there's no dependencies to resolve.
With only a single binding, let-flow
would be effectively the same as writing:
(when-let [foo @some-deferred]
(do-something foo)
A multi-binding let-flow
is possible, but it's not clear if the termination criteria should be all non-nil or any non-nil.
On top of that, unlike single-threaded code, independent let-flow
bindings can run in separate threads, making termination tricky/impossible. It would have to be completely serialized
Well, perhaps this is not the intended usage of the macro, but I find let-flow
very useful to compose deferred values into complex code, instead of recurring to chain
and lambdas. (Similar to using do
notation in haskell instead of >>=
).
(let-flow [value some-deferred]
(foo value)
(bar value))
;; although in this case we could have just gone with
(chain some-deferred
#((foo %) (bar %)))
Because of this, I often end up with situations in which let-flow
and if
are being used exactly like let
and if
in the if-let
macro:
(let-flow [value some-deferred-tuple]
(if value
(let [[x y z] value] z)
(foo)
))
So I wonder if it is worth introducing an if-let-flow
construct for those cases.
(if-let-flow [[x y z] some-deferred-tuple]
z
(foo))
Something like this:
(defmacro if-let-flow [bindings then else]
`(let-flow [value# ~(second bindings)]
(if value#
(let [~(first bindings) value#]
~then
)
~else
)
))
(defmacro when-let-flow [bindings & body]
`(let-flow [value# ~(second bindings)]
(when value#
(let [~(first bindings) value#]
~@body
)
)
))
So, you're not interested in a multi-binding version of if-let
and when-let
?
In that case, you really don't need new macros. It's probably simpler to use core if-let
/when-let
and deref the sole deferred. E.g., instead of if-let-flow
, do:
(if-let [foo @some-deferred]
(do-something-with foo)
(log/error "foo is false or nil"))
It'll effectively be the same thing.
I guess you don't get async in that case, so if you need to ensure it runs in the background and/or returns a deferred, it would be:
(future
(if-let [foo @some-deferred]
(do-something-with foo)
(log/error "foo is false or nil")))
Still, I'm not quite sure it's worth adding to the manifold API. Like I said, the let-flow
value is in figuring out the dependencies.
It would be nice to have constructs like clojure's
if-let
andwhen-let
but made forlet-flow
instead.It's simple enough to just implement this once needed, but nice to have by default.