@seancorfield we recently updated org.clojure/core.cache to 1.2.254 and apparently https://github.com/clojure/core.cache/commit/c15b60d09f417636b4e9239fbb421ef8ba4feb6f makes the cache store exceptions for keys, which didn't happen before.
https://gist.github.com/jpalharini/d92656a06b281f0ba87c459b346f598c will store a cache entry for "throw" in 1.2.254, but not store it in 1.1.234.
I'm wondering if this is actually the expected behavior considering we want to ensure value-fn/wrap-fn is called at most once, and evicting invalid entries is supposed to be done on the consumer side, or perhaps by implementing a "validating" cache.
Interesting. That was not an intentional change in behavior -- but I will note https://clojure.atlassian.net/browse/CMEMOIZE-31 which was raised against core.memoize for a similar issue: exceptions are cached.
Can you create an Ask with details and reference both CCACHE-65 and CMEMOIZE-31 and I'll have a think about solving both? (I was already investigating CMEMOIZE-31)
Ask = https://ask.clojure.org
Sure! I'll do that by tomorrow at the latest.
Ah, it doesn't (technically) cache an exception, it caches a delayed fn invocation, and the invocation throws when fetched from the cache. Which is the same bug as core.memoize already had, because it takes a similar approach. I wonder if I can switch to some sort of promise/deliver implementation that doesn't deliver exceptions...?
Yep, it caches the delay. Sorry, I should've been clearer.
https://ask.clojure.org/index.php/14965/clojure-core-cache-caches-exceptions-as-of-version-1-2-254
How many clojure.core functions/macros does clojure.core/println depend on?
1️⃣ 3
2️⃣ 12
3️⃣ 42
4️⃣ 85
5️⃣ 117
React with your answer! 👇
requiring-resolve: 166 is the largest
would be interesting to see a DOT graph of the dependencies 🤔
I could do that pretty easily, but so could you. Here's the data for you. https://github.com/gloathub/gloat/blob/main/build/clojure-core.yaml
PS I'm fascinated by your surname. 😄
böws döwn! 😂
I feel like the graph for the entire core library is going to be extremely busy.
Maybe just start with a dot graph for println
And if you gaze for long into an abyss, the abyss gazes also into you.
omg
What is M?
I think those are supposed to be various macros, but `clj-yaml` seems to parse I don't know how to write code.foo/M as M
So it ended up combining several ../M into one.
you can almost see something from this. perhaps I'll see if I can graph the dependencies of a particular function, if it looks any clearer.
@souenzzo in the https://github.com/gloathub/gloat/blob/main/build/clojure-core.yaml data I added /M to the macros and /S to the special forms
They could just be removed here.
I can make out concat on that middle one
Many macros use concat. Not sure if your algorithm consider ~@ as a concat.
I got the data by scraping the Glojure AOT code, where I think macros are expanded.
@nbtheduke
https://gist.github.com/ingydotnet/564eb6757a25cabd88318abdb118e7c1
https://gist.github.com/ingydotnet/44f50129feba399ea4403e5edb4c906c
Bask in the insanity of println 😂
BTW -Xprune works now with 50% size reduction and 80% startup time reduction 🙂
holy crap lol
YS's ys.std/say avoids clojure.core print calls but still needs to call apply and str and a few others
It's so nice to have a clear lens into this stuff.
I think gloat -Xdeps will be super useful even to non- #glojure people.
too many hah
it's a fun pop trivia quiz! take a guess!
Afterwards I'll show you how many deps every cc form has 🙂
I'm not going to count!
i actually ran into this when writing a formatter for Project Fluent files last year. I couldn't find the source of the the poor performance (vs a 1-to-1 version in java) until i tracked it down to calling pr-str instead of Writer/.write.
do you only mean first-order dependencies? technically printing bottoms out at print-method / print-dup which are multimethods (i.e. arbitrarily open to extension) so i'd say the answer is "it depends" 😄
I found out the answer originally when I was compiling a Clojure to Go code to binary file and wondering why it was so huge. See https://gloathub.org/blog/2026/02/22/introducing-gloat-and-glojure/
My source code only used println and some other trivial function like inc.
I removed the rest of the code, but it was still a pretty huge binary after that.
> do you only mean first-order dependencies? No, I mean the recursive dependency tree. Unique functions/macros of that tree.
Okay, time's up. Here's the answer. https://gist.github.com/ingydotnet/0423ea7fbcfc653393f598eb6ee66501#file-clojure-core-deps-counts-yaml-L413
a winner is me!
@nbtheduke I honestly thought everybody would copy you. 😄
i was worried it was higher!
requiring-resolve is 162!! https://gist.github.com/ingydotnet/0423ea7fbcfc653393f598eb6ee66501#file-clojure-core-deps-counts-yaml-L461
I'm working on a system to do some tree shaking on the AOT compilation process to go code.
Pretty much every binary executable is going to have a println. All it needs is Go fmt.Println
For general stuff, not 85 extra functions.
Since most of my input is YAMLScript anyway, YS has say for println So I can just make that do the fast thing. Can't really mess with clojure.core/println
I guess for Clojure tree shaking purposes, people could just replace println in their ns with a function that does Go interop to fmt.Println
I should be able to get that done this week. gloat -Xprune foo.clj && ls -lh foo
Right now all the binaries are weighing in around 65MB. I think that's stripped but I'm not 100%.