Fork me on GitHub
#unrepl
<
2017-05-15
>
cgrand07:05:30

@dominicm on why I consider bound-fn unfit?

dominicm07:05:24

@cgrand mmhm, and what you think more suitable.

cgrand08:05:48

JS being single threaded doesn’t mean you can’t have several logical processes (cooperatively) sharing the thread. In many cases the callback you pass is the continuation of the current process. On the JVM this style is infrequent because there are preemptive threads. So bound-fn is ok for the occasional call. In js you wouljd litter your code with bound-fn calls. Furthermore bound-fn flattens the dynamic bindings stack. Which makes impossible some continuation stuff. E.g. in Clojure (with-open [f ...] (do sync IO)) can’t be translated to (with-open [f ..] (.on f "data" (bound-fn ...))) because resource reclamation must happen in the continuation (otherwise by the time the callback is called the resource is already disposed.

cgrand08:05:17

Basically I think the callback-as-continuation scenario needs special support for dynamic variables and for the other dynamically scoped feature: try/catch/finally

dominicm12:05:04

I see, interesting. A difficult thing to achieve though! Although very simple if we were to generate ES.next code (with the new async functions)

pesterhazy14:05:32

could you explain how that would help @dominicm ?

dominicm15:05:47

@pesterhazy my understanding is that try/catch works with e.g. async/await

dominicm15:05:54

That might be wrong though now I think about it

richiardiandrea16:05:41

Isn't the continuation approach exactly what cljs-zones does?

richiardiandrea16:05:10

I might have misread it from the Klipse example above

richiardiandrea16:05:45

Reading as we speak 😀

cgrand19:05:09

I wouldn't say exactly. Plus I believe the prototype-based implementation is flawed: a set on a dynamic var bound in an outer scope should survive to the current scope

richiardiandrea19:05:32

@cgrand I think that is exactly the point of using prototypes, but I am not a JS master so maybe we can summon @darwin to this channel 😄

cgrand19:05:46

@richiardiandrea (binding [a 1] (binding [b 2] (set! a 3)) a) should evaluate to 3 not to 1.

richiardiandrea19:05:49

(ns zones.test
  (:require [zones.core :as zones :include-macros true]))

(zones/binding [a 1] (zones/binding [b 2] (set! a 3)) a)

richiardiandrea19:05:57

this evaluates to 3

richiardiandrea19:05:47

again, not the author here, but prototypes inherit properties so this can go as deep as needed...

cgrand19:05:04

And if you replace set! by zone/set! And plain a by (zone/get a) — sorry to use you as a repl but I only have two thumbs

richiardiandrea19:05:16

np let me check 😄

richiardiandrea19:05:10

(ns zones.test
  (:require [zones.core :as zones :include-macros true]))

(zones/binding [a 1] (zones/binding [b 2] (zones/set! a 3)) (zones/get a))
=> 3

richiardiandrea19:05:59

no zones/get is the same

(ns zones.test
  (:require [zones.core :as zones :include-macros true]))

(zones/binding [a 1] (zones/binding [b 2] (zones/set! a 3)) a)
...this one does not work as expected actually... so you need a zones/get

richiardiandrea19:05:25

I like, it is good to see if we can break it 😉

cgrand19:05:13

Hmm I'll have to look at the impl because the prototype chain only works for getting a property. All sets are shallow.

cgrand20:05:15

So the protochain is explicitly walked. Would be interesting to benchmark as this kind of behavior used to trigger perf penalties (because of cache invalidation).