Fork me on GitHub
Karol Wójcik13:12:31

Q: When I'm requiring the ns, the Clojure runtime will load all the functions from that namespace, right?


Yes, unless a function definition is wrapped in a conditional, or somehow excluded otherwise:

(when false
  (defn ...))

Karol Wójcik13:12:57

Right! Thanks!


user=> {:a.b.c/a :a.b.c/b}
#:a.b.c{:a :a.b.c/b}
user=> (pr-str {:a.b.c/a :a.b.c/b})
"#:a.b.c{:a :a.b.c/b}"
Should I or should I not add support for this to an EDN parser?


I am not an author of the EDN specification, so have no authority in this matter. I can say some things that are perhaps already obvious to you, so maybe unhelpful, but nevertheless true. The short-hand of putting a namespace before the { character of a map whose keys are all namespace-qualified, and all have the same namespace qualifier, was introduced after the EDN specification was written, and a reading of does not mention or even imply (to my reading) that this is part of EDN. This suggests that an EDN parser should not support it.


On the other hand, what one might consider a reference implementation does support it:

=> (clojure.edn/read-string "#:a.b.c{:a :a.b.c/b}")
#:a.b.c{:a :a.b.c/b}


it's a clojure reader macro, not part of edn itself i believe


I think some more statements that are true are that despite some people wanting the EDN spec to nail down all of these details, the EDN authors seem unlikely to be willing to change the EDN spec to do so. Could that change in the future? Sure, if the authors decide to. It hasn't happened in the 8 years since it was published, though, so seems unlikely to any time soon.


There are some similarities here with some people wishing that there were a very precisely written specification for Clojure the programming language. That is a much more complex task than a tightly specified syntax for a data interchange format, so these are not identical situations, just similar.


my current thought is that #:a.b.c{:a :a.b.c/b} is invalid edn, which means if i added support i would be supporting a superset of edn


which is better than being incompatible

Ben Sless18:12:22

Can you split the implementation between a lean core which implements only the specification and additional features?


i see no reason why i can’t. The code for that is here. I just need to flag what happens if i find a keyword after the #


published with the option enabled by default


(also a 539 line recursive function is a new record for me)

Ben Sless17:12:10

philosophical / stylistic question, how do you choose the root namespace layout for your project? I see plenty of options around • java like, • user-prefix user.tool • intent / semantic prefix next.jdbc • old-school: myproj.core Would appreciate some pros/cons and your general thoughts

Alex Miller (Clojure team)18:12:03

If you are writing a lib, you will be mixing with other libs and should maintain a globally unique space that you control to some degree, either by (reverse) dns, or by trademark, or by conveyed identity by a third party, like github

Alex Miller (Clojure team)18:12:45

Generally that's probably similar to your group id in maven coord

Alex Miller (Clojure team)18:12:22

If you're writing an app and not publishing it for others to use, do whatever you want (as long as it's unlikely to collide with the lib approach above)

Ben Sless18:12:50

So the schema for could be thought of as user.domain.functionality.api?

Ben Sless18:12:19

I have libs in mind at the moment

Alex Miller (Clojure team)18:12:40

Sure although domain and functionality are pretty vague and totally up to you

Alex Miller (Clojure team)18:12:25

It needs to be sufficiently unique for the user/org

Ben Sless18:12:31

So the creative project names handle it by way of just being cool (promesa, jsonista, etc)

Ben Sless18:12:14

-> unless I come up with a cool project name, I should probably prefix with my user/org


At this point, even if you come up with a "cool project name", I think a user/org prefix is a good idea. I don't think it necessarily needs to be full reverse DNS (unless your user/org prefix is pretty generic already).


I agonized over next.jdbc vs seancorfield.jdbc or for quite a while, and polled the potential users before I decided to go with just next.jdbc.


The reason we have so many myproj.core namespaces is that lein never required qualified or multisegment project names and then just slapped .core on the end of any single-segment names.


That's why clj-new requires either user/project or user.project so it can have a qualified main ns without .core. Some folks have complained and I've just expanded the explanation of why it does this 🙂

Ben Sless20:12:56

I feel more confused than when I started


Because the answer is "it depends"? 😁


Just my 2 cents. I like it when the main api ns is just the name of the lib (with whatever prefix options you have available). nippy -> taoensso.nippy, uri -> lambdaisland.uri , etc... If then the prefix also matches also the artifact. Perfect.

Ivar Refsdal18:12:22

If you are going to publish a library on Clojars, I think you should go with what you call java style. From April this year Clojars started That does not mandate any particular layout for the namespace, but I rather strongly think they should match. E.g. on the following projected hosted at I'm using com.github.ivarref as namespace root, and com.github.ivarref as the (verified) group id.

Karol Wójcik18:12:54

What are actual benefits of binding Clojure vars in static fields, is it for the performance optimization on the Compiler level? See


I’ve never seen a discussion about it, but optimization is the likely answer.


No need to re-allocate on every invocation.

Karol Wójcik18:12:53

I think the another feature of this is the GraalVM can cleanly track not used classes (not used Clojure functions) and remove them since each one is bound to a static var. cc @U04V15CAJ.

Karol Wójcik18:12:35

@U064X3EF3 Could you elaborate?

Alex Miller (Clojure team)19:12:19

If it's a static field you load it once vs loading it every time you invoke

Karol Wójcik19:12:30

Got it. It's a performance optimization then. Trading the startup time for maximum performance, right?


I’m not sure that framing is quite accurate. It depends on what you choose to call “startup.” If that class is never loaded, it does not contribute to startup time at all. If that class is loaded and has its method invoked, then then net time added is zero. The only time you incur additional overhead is if you, for some reason, load the class, but never use it.

Karol Wójcik20:12:07

But all the classes (compiled functions) are loaded via the __init class when (:require [clojure-string]) is used in this case. Which means that the initialization of each instance in static slows the startup time compared to the hypothetical situation when the function implementation would be instantiated on the actual call of a function.

Karol Wójcik20:12:07

You can use only one function from clojure.core and your startup time is a sum of instancing each var in the namespace during the implicit load.


Yeah those fall into the latter category I mentioned. It’s fair to point out that clojure.core is particularly affected by this behavior.

Karol Wójcik20:12:05

It's only about clojure.core. When using any clojure library rarely one uses the 100% of it's functions.

Alex Miller (Clojure team)20:12:17

There is an old branch for lazy var loading that avoids this cost, maybe will eventually be revived. At the time it had the downside of making regular invocation a bit slower due to the load check. There are better jvm tools available now that could mitigate this.

Karol Wójcik10:12:06

What tools do you have in mind?