clojure-dev

Issues: https://clojure.atlassian.net/browse/CLJ | Guide: https://insideclojure.org/2015/05/01/contributing-clojure/
dominicm 2020-12-14T08:09:21.356400Z

is it a bad idea to use the clojure compiler options in my code, something like so:

(if (:direct-linking *compiler-options*)
  handler
  #(apply handler  %&))
Thinking about the impacts this might have on hot swappable code.

borkdude 2020-12-14T08:44:04.356900Z

@dominicm Is this to circumvent direct linking? In that case you can make your var ^:redef or ^:dynamic if it should be a dynamic var.

2020-12-14T09:14:57.359400Z

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.

dominicm 2020-12-14T09:22:08.360800Z

@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.

borkdude 2020-12-14T09:24:36.361600Z

The above still applies to your situation I think

Ben Sless 2020-12-14T09:30:13.362Z

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

dominicm 2020-12-14T10:06:18.363100Z

@ben.sless yes, I'm wondering if direct linking could be used as a proxy for switching between those two routers, yes.

dominicm 2020-12-14T10:06:36.363700Z

@borkdude I've not heard of redef, so I need to check that out.

borkdude 2020-12-14T10:07:05.364100Z

@dominicm It's documented here: https://clojure.org/reference/compilation#directlinking

borkdude 2020-12-14T10:08:08.366100Z

You can probably even get away with making that metadata dynamic based on dev or prod

dominicm 2020-12-14T10:08:16.366400Z

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.

borkdude 2020-12-14T10:08:47.367Z

Then why did you bring up direct linking?

borkdude 2020-12-14T10:09:49.367700Z

#(foo 1 2 3) will see redefinitions of foo, but (partial foo ...) won't

dominicm 2020-12-14T10:10:49.369100Z

I was thinking that direct linking would be an appropriate flag to use to switch between the two.

seancorfield 2020-12-14T19:24:04.371200Z

@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).

dominicm 2020-12-14T19:27:53.372200Z

@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.

seancorfield 2020-12-14T19:30:31.373200Z

@dominicm That seems to indicate that indirect use is faster than direct use 👀 and neither of those tests use a Var reference?

2020-12-14T19:34:48.373400Z

"the difference appears insignificant."

borkdude 2020-12-14T19:36:06.374Z

And the ability to hotfix a var in production might outweigh the small perf hit :P

2020-12-14T19:36:41.374500Z

that is a quote from the repo readme

borkdude 2020-12-14T19:37:02.375100Z

I understood that

2020-12-14T19:37:20.375500Z

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

2020-12-14T19:38:15.376300Z

so you should be very careful about using that to justify making decisions about direct linking and var reference usage

2020-12-14T19:40:16.377500Z

my understanding is directly linking is mostly a win around avoiding the volatile field which vars use to hold data

2020-12-14T19:40:40.378Z

reading and writing a volatile is, relative to a lot of user code, very cheap

2020-12-14T19:41:07.378800Z

but I believe it limits the amount of inlining the jvm jit can do

2020-12-14T19:42:46.380700Z

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

borkdude 2020-12-14T19:45:47.382900Z

for these cases you could maybe turn on direct linking temporarily, compile the function with hot loops and then disable it again

borkdude 2020-12-14T19:47:31.383300Z

but that would get confusing if you patch a var that's used in the body of such a function

borkdude 2020-12-14T19:47:36.383500Z

and elsewhere

borkdude 2020-12-14T19:48:31.384200Z

you could program against this by de-refing the vars outside the loop and then using the bindings in the loop as well

borkdude 2020-12-14T19:49:05.384800Z

(let [x @#'inc] (loop [] (x 2)))

borkdude 2020-12-14T19:49:26.385200Z

or even without @#' this works already

borkdude 2020-12-14T19:50:43.385700Z

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?

borkdude 2020-12-14T19:52:55.385900Z

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

2020-12-14T19:53:56.386300Z

@borkdude I am not sure this is a conversation for #clojure-dev

borkdude 2020-12-14T19:54:05.386500Z

sorry

2020-12-14T20:00:51.386600Z

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

2020-12-14T20:02:21.386800Z

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

borkdude 2020-12-14T20:03:02.387Z

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.

alexmiller 2020-12-14T20:41:51.388600Z

Direct linking also directly affects bytecode size and thus load time because it does need to load or store vars in fields

2020-12-14T20:50:25.389800Z

Ah of course, should have remembered that, the impact to load times is why we have it turned on at work

Ben Sless 2020-12-14T20:59:33.390100Z

I have also found it decreases GC pressure