Fork me on GitHub
#missionary
<
2022-01-03
>
Panel11:01:49

What would be clean way to cancel a task at the repl ?

ribelo11:01:50

IIRC task is a fn with cancelation at 0 arity

Panel11:01:16

Thanks, I was using something like (def result (m/? some-task)) but it's better to do (def task (some-task prn prn)) and then I can cancel task in flight

Dustin Getz16:01:45

i propose the special case of m/? outside of m/sp m/ap should be removed, it seems to have no value in prod code, it is JVM only, and the repl convenience use case is superseded by RCF async tests which let you work directly with async types at the REPL on any platform. It's also non-obvious and the "magic" edge case is surprising and requires explanation for new users

Dustin Getz16:01:02

it also makes it too easy for a new user to throw away the cancellation callback (and not even realize it is there), that should not be the path of least resistance

leonoel08:01:49

Just to be clear ? in thread mode supports cancellation via thread interruption, like any blocking call should. The problem is, no clojure repl implements evaluation interruption properly and you can observe that on any blocking call, not only ?

clojure-spin 2
leonoel08:01:54

> it seems to have no value in prod code interop with something that expects a blocking function, e.g ring request handlers

Panel10:01:14

"The problem is, no clojure repl implements evaluation interruption properly" That's very valuable to know, if you have a safe way to use ? with a repl let us know. In the meantime I juste use (def cancel (task success failure))

Dustin Getz19:01:18

If I'm understanding correctly, can the operator for "pull value out of container reference and block", if the real world use case matters, have a different name? (From this perspective the task is a reference, right?) This deref-like operation is impure, unlike m/? inside process block

leonoel20:01:33

they have the exact same semantics and they're both impure

leonoel20:01:47

run the task and park current computation until completed

leonoel20:01:29

I think it is well defined, I understand the potential confusion but that looks more like a teaching problem to me

leonoel20:01:41

the tutorial may better not encourage usage of ? at the REPL

ribelo20:01:58

IMHO missionary's learning curve is more than steep, but this is not due to the api itself, but rather to the fact that FRP is simple but not easy

ribelo20:01:39

hiding complexity may make things easier, but it will not simplify anything

Dustin Getz19:01:27

I am struggling to reproduce the conclusion that the m/? abstraction is impure (other than from an internal implementation perspective). Upon further thinking I propose my statement (that m/? is pure) was ill formed: IIUC, from userland perspective, m/? is syntax (compile-time marker) and can only be considered as a unit with m/sp. At which point it is an alternative syntax for fmap and bind as per https://clojurians.slack.com/archives/CL85MBPEF/p1606665937005100

leonoel18:01:39

One benefit of having the same operator for threads and fibers, you can write this kind of macros once and it works in both contexts https://github.com/leonoel/missionary/blob/master/src/missionary/core.cljc#L402

mjmeintjes21:01:43

I found https://github.com/riverford/objection to be useful for managing repl tasks and ensuring they get cancelled as needed:

(defn call-single
    "Use for running tasks - runs it once under the name, cancels if it exists already"
    [key task]
    (obj/stop! key)
    (obj/register
     (task #(println "FINISHED" %)
           #(println "ERROR" (ex-message %)))
     {:stopfn (fn [c]
                (c))
      :aliases [key]}))

  (call-single
   ::call
   (m/sp
    (try (m/? (m/sleep 1000))
         (println "DONE")
         (catch Exception ex
           (println "EX" (ex-message ex))))))