v3 question. In Chrome, I get the following. Not in Safari or Firefox. Is it normal, or have I likely misconfigured something?
Connecting...
14:19:04.779 electric.cljs:35 Reactor failure: missionary.Cancelled {message: undefined}
It seems to work fine.you're not the first to report, i have escalated it internally we will clean this up
For me it only happens when I live-reload code. Also (perhaps unrelated) some interactions freeze for about 1sec when I have Chrome developer tools open, but are instantaneous otherwise. I can publish the repo where this happens if it helps
Chrome dev tools is a real resource hog, it slows things down enormously in our app. But yeah, I think you’re right, it’s possibly a live reload thing. Maybe “cosmetic” in the grand scheme of things even, seeing as the other two browser don’t have a problem, and I’m not seeing any particular problems that I would suspect to be Chrome-only.
Another question as I’m slowly requiring some existing files. How should I approach this interaction with Encore (via Telemere, Nippy, etc.)?
cannot-expand [co.multiply.client co.multiply.module.agent.query co.multiply.app.util.anomaly taoensso.telemere taoensso.encore] (#'taoensso.encore/defalias get-truss-data taoensso.truss/get-data nil nil)
:failed-to-analyze [co.multiply.client co.multiply.module.agent.query co.multiply.app.util.anomaly taoensso.telemere taoensso.encore]
:failed-to-analyze [co.multiply.client co.multiply.module.agent.query co.multiply.app.util.anomaly taoensso.telemere]
:failed-to-analyze [co.multiply.client co.multiply.module.agent.query co.multiply.app.util.anomaly]
:failed-to-analyze [co.multiply.client co.multiply.module.agent.query]
:failed-to-analyze [co.multiply.client]
Unexpected error (NullPointerException) macroexpanding e/defn at (co/multiply/client.cljc:24:1).
Cannot invoke "java.util.concurrent.Future.get()" because "fut" is nullsubscribing to updates as well. @henrik were you able to find a workaround with telemere?
I'm looking into this, if I require malli.core and use it as e.g. (malli.core/validate [:map] {}) in electric I don't see the failure you did. Do you have a more specific repro?
For Malli, it’s specifically malli.core/=> it complains about, ie., spec for IO to functions. For Telemere, it’s basically anything, since it’s all macros that expand into something straight out of the Egyptian Book of the Dead. In v2, the workaround was basically something like (#(te/log! …)) rather than te/log! directly from Electric.
I’ll try to produce something that’ll trigger it predictably.
what changed since v2 is we ship our custom cljs analyzer and it deep analyzes requires from your electric namespaces. The workaround Dustin explained is to not require the problematic namespaces in electric namespaces, i.e. if you have foo.cljc with malli and electric code, split it in 2 namespaces foo_with_malli.cljc and foo_with_electric.cljc and don't require malli in the electric ns. This is a quick fix until we figure out all the kinks. At the same time I do want to fix the bugs so if you have good repros of common libraries those are very helpful
Right, I’m not calling Malli or Telemere directly from an Electric NS, but I do reach into another NS which does, where there’s no Electric to be found.
Or rather it’s foo_with_electric -> foo_without_anything -> foo_with_malli .
I dropped this from the malli readme into an electric file and did not trigger the bug
yes, the analysis is transitive
ok encore crashes immediately 😉
This is the cascade of imports from the three files. The problem occurs when I uncomment the #_[co.multiply.module.agent.query :as agent.q] line in the Electric NS.
Perhaps pertinent to this is that I can do this with hot reload, and it seems to work, but booting from scratch with [co.multiply.module.agent.query :as agent.q] uncommented results in the error above.
encore
(defmacro when
"Supersets `core/when`
🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈Encore is the bane of my existence; full of black magic, backwards incompatible, and pervasively used throughout the Clojure community.
Why do we analyze transitive modules? I thought we just need to inspect defs visible from an Electric scope
if an electric code calls foo/bar we need to know whether that's a macro or a defn (or both). If foo/bar is defined as (taoensso.core/defalias bar ...) we need to know what taoensso.core/defalias is and possibly expand it to figure out if bar will be a macro or a defn
Is there a clear example of why this absolutely has to be done, rather than just forcing unusual library bullshit to be wrapped in ((fn [] ...))
cljs core functions often have a function and a macro definition at the same time. E.g. + might compile to a cljs + function call, or to (js* "+ {} {}" a b) (pseudo-coding here), to produce tighter js that can be better optimized. We want the opposite, we prefer to compile to function calls because a) it's more generic, i.e. will more likely work on both peers and b) the macroexpanded code is usually larger (inlining calls for speed) which for us means a larger DAG that is actually slower.
So it boils down to cljs prefering macros while we prefer functions. We used the stock cljs analyzer but had to fight against it because of this difference. Today we have a small analyzer catered to our use cases that is easier to maintain than using the cljs one. But it's not mature yet, we need more real world code to train it on.
There's also room for improvement in the analyzer, maybe it could be lazier, short-circuit sooner etc.
I certainly don't want users to wrap in IIFEs, we should increase our compat
I’m talking out of my ass about things I don’t understand here, but I remember Alex saying that for the core.async IOC macro, they basically reimplemented the Clojure(non-script) analyzer from Java to plain Clojure. Perhaps there’s something, analyzer-wise, to get from there.
my question is specifically about the transitive case, + in an electric block is a direct refer not transitive
its clear that we need to analyze the first breadth level of :require statements because their definitions can appear in an electric block directly
I understand the problem with encore. I cannot hit the malli error. Could you share which version are you using?
The "fut" is null error comes from macros that try to read cljs internal compiler state (at macroexpansion time). You don't happen to do that in your code, do you? I'd expect some malli internals to fiddle with it but did not find the culprit yet
Amazing. No, not intentionally at least. We’re using the malli.experimental Prismatic function schema lookalike, and it looks like it’s reacting to that callsite in particular.
I.e., this syntax:
(mx/defn hello :- string?
[name :- string?]
(str "Hello " name "!"))
(hello "Peter")
(hello :peter)Thanks. Can you also paste the lib version from your deps.edn
metosin/malli {:mvn/version "0.17.0"}Inserting myself just to get updates. And hi Peter, hope you’re well!
tested both on server and client, telemere will work with the next snapshot release. No wrapper tricks needed
I did not report but I fixed the issues for encore (transitively telemere) and malli. Latest should just work
fixed for the transitive case right? i can't log from within electric code? the v2 wrapper trick (#(te/log! …)) is still giving me this error: IllegalArgumentException: No matching ctor found for class taoensso.telemere.impl.Signal
at any rate, thank you for the workaround
I didn’t know that Peter had fixed it, so I haven’t retried. I’ll give it another go.
I see, I will check telemere directly , didn't do that tbh
I can repro the telemere Signal ctor bug
Looking at defalias, it’s a macro:
"Defines a local alias for the var identified by given qualified
source symbol: (defalias my-map clojure.core/map), etc.
Source var's metadata will be preserved (docstring, arglists, etc.).
Changes to Clj source var's value will also be applied to alias.
See also `defaliases`."Barely a day goes by where Encore isn’t causing me one headache or another.
Could it be that it’s behind a :clj -scope?
#?(:clj
(defmacro defaliasActually, same for Malli:
:cannot-expand [co.multiply.client co.multiply.module.agent.query co.multiply.app.util.anomaly] (#'malli.core/=> new-anomaly [:function [:=> [:cat anomaly-categories-spec] anomaly-spec] [:=> [:cat anomaly-categories-spec string?] anomaly-spec] [:=> [:cat anomaly-categories-spec string? [:or nil? map?]] anomaly-spec]])
:failed-to-analyze [co.multiply.client co.multiply.module.agent.query co.multiply.app.util.anomaly]
:failed-to-analyze [co.multiply.client co.multiply.module.agent.query]
:failed-to-analyze [co.multiply.client]
Unexpected error (NullPointerException) macroexpanding e/defn at (co/multiply/client.cljc:23:1).
Cannot invoke "java.util.concurrent.Future.get()" because "fut" is nullprobably electric compiler issues, here is an explanation with workaround:
in any file with an e/defn, the Electric compiler will analyze the namespace and further analyze all dependencies in the :require statement in order to understand any definitions referenced in an e/defn body. If you need to prevent that (e.g. due to the above issues), you can isolate electric code into smaller namespaces, rather than for example putting an e/defn (or e/boot!) in your Big Dependency Injection Server File that contains 1000 :require statements
so like, have a tight electric entrypoint namespace that injects the minimum dependencies (or takes them as parameter), and then your electric views only :require things they actually need
in the case of Malli and Encore, they are common enough that Electric will need to be fixed, we may not have seen those dependencies before
For example, we saw #^{} for the first time recently in https://github.com/clojure/math.combinatorics/blob/50318f0be6f6577f1f14d03827d96f0ba486aa56/src/main/clojure/clojure/math/combinatorics.cljc#L8, it is https://github.com/clojure/clojure/blob/fb22fd778a272b034684a4ee94509552b46ee8a9/src/jvm/clojure/lang/LispReader.java#L111 but electric has to analyze it
In this case it’s a CLJC file, but it has no Electric forms in it. In fact, it’s a CLJC file which requires another CLJC file which requires Malli, so I’m hesitant to think that moving it one step further away yet would make any difference.
I.e., co.multiply.app.util.anomaly uses Malli. It’s required by co.multiply.module.agent.query, which originally had Electric code in it in v2 to colocate with their CLJ counterparts, but which I’ve now all deleted in order to put back piecemeal, which is required from co.multiply.client which does have Electric forms.
update: we're working on it this week
Oh, I was sketching out workarounds, but that’s fantastic to hear. Thanks!
Lightning talk: https://share.descript.com/view/nJkFVXo15lM
Very well presented! I never noticed that "with lambda you can build an OS, or Emacs" is a puchline before
(Nothing new here, it's from last summer)