Fork me on GitHub
#hyperfiddle
<
2023-09-24
>
nivekuil03:09:06

foreshadowing

nivekuil03:09:47

context: trying to avoid designing a macro-based api with a dynamic var to hold context, but I think it might be the only way to get good ergonomics, since we're stuck with compile-time dependency injection

Dustin Getz11:09:56

what is compile time DI, are you referring to the Electric compiler?

👍 1
Dustin Getz11:09:37

That opinion that Dynamic scope is RT is controversial, i’ve mostly had it beaten out of me (by Leo and others). Regardless of if it is RT i think it’s still great, it just interacts terribly in ordinary clojure with lazy-seq

nivekuil17:09:51

so the solution to making dynamic scope not suck is to not do it in "ordinary clojure", so the electric dyn vars are only bound within the electric program?

nivekuil17:09:48

arguably lazy-seq is the bigger mistake.. it's a really idiosyncratic thing to be idiomatic, other languages get by fine without them

nivekuil18:09:34

I guess this is why you cannot bind dynamic vars inside electric programs. already ran into that trying to use with-out-str

Dustin Getz22:09:52

an important difference between Electric dynamics and Clojure dynamics is that Electric dynamics have the Electric RAII lifecycle, making them more or less equivalent to Component/Mount as i believe we discussed last month

Dustin Getz22:09:21

and since Electric code does not make use of the clojure seq abstraction at all (due to it not being reactive), the bad lazy seq interaction is avoided

Dustin Getz22:09:28

Clojure dynamics have other problems with respect to how they interact with JVM concurrency and specifically about how Clojure’s “binding conveyance” between threads has serious shortcomings, Leo wrote a rant about this that I’ll have to go find. Again, Electric doesn’t use Clojure’s concurrency so those interactions are also avoided

Dustin Getz22:09:07

with respect to binding Clojure dynamics from Electric programs (breaking with-out-str) I need to go look at our internal issue tracker to remember our stance on that and the details/options

xificurC06:09:41

re electric -> clj(s), reactive vars are conveyed where possible

(e/def db (e/watch !conn))
(e/defn App []
  (d/q [] db) ; obviously works, passed as a positional argument
  (#(prn db)) ; also works, we analyze and convey

(defn my-transact [] ; not electric
  (d/q [] db))       ; not possible to convey

leonoel07:09:03

my opinion on lazy sequences and dynamic vars in clojure : • the dynamic var idea started with good intentions but binding conveyance completely ruined it. Without binding conveyance, dynamic vars are equivalent to thread local state, which has some valid use cases. Using thread local state for DI is a bad idea because it breaks everything that relies on referential transparency - not only lazy sequences, really all kinds of deferred evaluation. If thread local state is what you need, use ThreadLocal because dynamic var performance is terrible (due to binding conveyance, even if you don't use it). To understand why binding conveyance is bad, consider this snippet : (with-out-str (future (println "hello"))) • lazy sequences are not bad but it should not be the default because laziness+memoization is almost never what you need, you generally need one or the other but not both, so you pay the performance overhead for nothing

nivekuil07:09:22

that's true, and in the two places I actually use lazy seqs the chunking works against me too

nivekuil07:09:10

we need to spread the word about eduction

leonoel07:09:33

eduction rocks

nivekuil23:09:49

how is compile performance for people? I feel like i've done something wrong, getting ~9s compiles for a small test project

nivekuil23:09:29

narrowing it down a bit, this seems weird

nivekuil23:09:42

seems like every dom/on adds 2 seconds? that doesn't seem right

Dustin Getz00:09:43

i’ve never seen that

nivekuil00:09:04

how can I debug the compilation more?

Dustin Getz00:09:09

you have proven that it is specific to this project?

nivekuil00:09:14

ah, it's actually the varargs that's triggering it

nivekuil00:09:21

varargs + dom/on

nivekuil00:09:50

(e/defn Foo [body & rest]
  (ed/on "click" (e/fn [_])))
4.33 seconds

nivekuil00:09:57

(e/defn Foo [body]
  (ed/on "click" (e/fn [_])))
1.63

xificurC06:09:40

today varargs expand https://github.com/hyperfiddle/electric/blob/0842e64e895b260707a532068dc7f35c147fb65f/src/hyperfiddle/electric.cljc#L247arguments. Reducing the number reduces the compile times, but we don't have a dynamic fallback case today so I have to make the cutoff somewhere

nivekuil07:09:31

a single instance of e/defn .. & with dom/oncurrently doubles my build time. IMO it is completely unusable right now

xificurC08:09:11

thank you for the feedback, we'll get back to this at some point

Dustin Getz10:09:41

what Peter is saying is that we probably want to land incremental compilation first which is our platform for future work on the build time

Dustin Getz10:09:40

the specific interaction with dom/on is also surprising, needs more analysis on our part

Dustin Getz10:09:21

Surely we can tune the varargs constant for now, and it feels like something O(n^2) may be happening as well

Dustin Getz11:09:14

Immediate workaround: lift to arity-1 function that takes a single list and destructure the list

nivekuil00:12:47

@U09FL65DK good to know, thank you!