This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # adventofcode (42)
- # babashka (37)
- # beginners (62)
- # cider (13)
- # clj-kondo (12)
- # cljdoc (1)
- # clojure (80)
- # clojure-australia (2)
- # clojure-dev (43)
- # clojure-europe (69)
- # clojure-italy (8)
- # clojure-nl (10)
- # clojure-switzerland (130)
- # clojure-uk (12)
- # clojurescript (23)
- # code-reviews (8)
- # crux (1)
- # cryogen (5)
- # cursive (6)
- # datomic (3)
- # duct (4)
- # emacs (12)
- # fulcro (60)
- # kaocha (7)
- # lambdaisland (4)
- # malli (4)
- # meander (1)
- # nrepl (31)
- # off-topic (2)
- # re-frame (16)
- # rewrite-clj (5)
- # shadow-cljs (11)
- # spacemacs (7)
is it a bad idea to use the clojure compiler options in my code, something like so:
Thinking about the impacts this might have on hot swappable code.
(if (:direct-linking *compiler-options*) handler #(apply handler %&))
@dominicm Is this to circumvent direct linking? In that case you can make your var
^:dynamic if it should be a dynamic var.
It is also possible that some parts of the Clojure code were compiled with direct linking enabled, and other parts were compiled with it disabled, and I am not sure whether and expression like that, even if it does appear to work, would actually "remember" which code was compiled how. clojure.core that most people use is compiled with direct linking enabled, and unless someone enables it, other Clojure code is compiled with it off.
@borkdude the broader context of this would be use with jetty or anywhere you pass a function for later execution. Making your ring functions reloadable without a reset.
I think reitit's docs have a solution for you https://cljdoc.org/d/metosin/reitit/0.5.10/doc/advanced/dev-workflow#an-easy-fix
@ben.sless yes, I'm wondering if direct linking could be used as a proxy for switching between those two routers, yes.
@dominicm It's documented here: https://clojure.org/reference/compilation#directlinking
You can probably even get away with making that metadata dynamic based on dev or prod
Okay, not after redef @borkdude. I'm not trying to bypass direct linking. I want to allow redefining a function in development, but not in production. But I'm really working around the fact I'm passing a function value around, rather than a var.
I was thinking that direct linking would be an appropriate flag to use to switch between the two.
@dominicm I'm curious if you've measured the overhead of using the Var in production vs a function value? We tend to just leave the Var references in place for handlers in our apps, but we do have direct linking enabled when we AOT compile for uberjars (so, in production, we can't redef functions on the fly in general anyway).
@seancorfield I have, https://github.com/SevereOverfl0w/direct-performance But the difficulties slip in cases like the reitit one where compiling a router is an expensive operation.
@dominicm That seems to indicate that indirect use is faster than direct use 👀 and neither of those tests use a Var reference?
but I should also point out, that the code in the repo is not testing direct linking, and is not testing using a var reference directly
so you should be very careful about using that to justify making decisions about direct linking and var reference usage
my understanding is directly linking is mostly a win around avoiding the volatile field which vars use to hold data
so in a hot loop, direct linking can be a huge performance win, because it lets the jit do more inlining, apply more optimizations, get more opportunities to inline, and so on
for these cases you could maybe turn on direct linking temporarily, compile the function with hot loops and then disable it again
but that would get confusing if you patch a var that's used in the body of such a function
you could program against this by de-refing the vars outside the loop and then using the bindings in the loop as well
but then you would get a lookup in the lexical context. I'm not sure how expensive that is, maybe similar to a var deref?
user=> (defn foo [x] (inc x)) #'user/foo user=> (time (dotimes [i 10000000000] (foo 1))) "Elapsed time: 6210.834273 msecs" nil user=> (time (let [foo foo] (dotimes [i 10000000000] (foo 1)))) "Elapsed time: 2476.871089 msecs" nil
I mean, I don't know, it just seems like a tutorial about how clojure compiles references to different kinds of names would be better somewhere like #clojure
I think of #clojure-dev to be more about the development of clojure, where that kind of thing can usually be assumed. But I don't know that I've seen a statement of purpose for #clojure-dev , so I may just be wrong
I was exploring a local variation of direct linking but I probably could have done that in private and not while thinking out loud. You're right.
Direct linking also directly affects bytecode size and thus load time because it does need to load or store vars in fields
Ah of course, should have remembered that, the impact to load times is why we have it turned on at work