Fork me on GitHub
#hyperfiddle
<
2023-11-15
>
henrik09:11:04

Is what I’m trying to do here impossible?

(e/defn ToyRunner
  [value]
  (e/server (println value)))

(e/defn ToyExample
  [Runner]
  (e/client
    (println 1)
    (e/server (Runner. 2))))

;; Run with,

(e/client (Toyexample. ToyRunner))

;; Unserializable reference transfer (client side)

(e/client (ToyExample. (e/server ToyRunner))

;; Unserializable reference transfer (server side)

henrik09:11:15

What I’m trying to do is to encapsulate named bags of server-side functionality and make them a pluggable/interchangable argument to a named bag of client-side functionality.

henrik09:11:31

Not a blocker btw; I can turn ToyExample into a macro to make it work.

Dustin Getz12:11:23

i see two issues here 1. electric fns/closures don't serialize and transmit (clojure's don't either) 2. electric fns are called from a single site, which means they collect their arguments to the site of the call. Here, due to this, ToyRunner is forced through a pointless roundtrip during which it fails to serialize. As you noted - you can work around with a macro. Even without falling back to macros there is usually a simple refactor that avoids this, which is why we deprioritized it. Note that e/def is multi-sited (each site has a version of the e/def), so top level functions like these can be resolved from either site. #1 will be fixed soon (the compiler can e.g. defunctionalize). #2 as well. This is likely coming right after differential electric (which is far more impactful and important)

👍 1
henrik12:11:46

Once differential lands, I expect I would write this very differently anyhow. Today, it’s dealing with calling various AI services and streaming back responses. I set this up (based on Peter’s advice) to be an accumulation into an atom, server-side, the value of which which is then streamed to a recipient, client-side. The client side handling turns out to be the same regardless, whereas the server-side bit varies wildly. So the goal was to bundle these into one client-side package, and many server-side packages. A macro is perfectly fine for now: it doesn’t need to be dynamic, just a bit more DRY than it would have been otherwise.

henrik11:11:44

Does :style have to be a literal? I get this works:

(dom/props {:style {:top "798px" :left "17.125px" :position "absolute"}})
I can’t get this to work:
(let [style {:top "798px" :left "17.125px" :position "absolute"}]
  (dom/props {:style style}))
Using master branch.

henrik13:11:53

Here’s the problem:

(defmacro style [m]
  (if (map? m)
    `(do ~@(map (fn [[k v]] `(new Style node ~k ~v)) m)) ; static keyset
    `(new Styles ~m)))


;; => 

(defmacro style [m]
  (if (map? m)
    `(do ~@(map (fn [[k v]] `(new Style node ~k ~v)) m)) ; static keyset
    `(new Styles node ~m)))
Styles is not arity-1.
(e/def Styles
  (e/fn* [node kvs]
    (e/for-by first [[k v] kvs]
      (Style. node k v))
    nil))

Dustin Getz18:11:15

i see, care to send a PR?

👍 1
👌 1
J13:11:26

👀 5
gratitude 3
2
👍 3
danbunea14:11:52

Thank you for sharing this as it contains several things that I could learn from: 1. electric + authentification 2. rama 3. polylith