clojure-dev 2026-10-23

Question regarding predicative inlining - still not sure what it's going to unleash or enable, but it does shut the door on some sort of dead code elimination or just figuring out by inlining that the form should be nil. Has that been considered? Any way around it?

Can always return a (do) or something like that.

yes but then it's not dead code I can eliminate, or even a branch I figured out should return nil Just as a stupid example with get-in, if I know the map is nil, I can replace the entire expression with nil

(assuming there are no side effects in the ks arg. FUN)

Why is (do) not dead code? It gets expanded during either macroexpansion or analysis phase by c.l.Compiler, I don't remember. Or you do you mean your own compiler of sorts?

It is dead code, I'm just conceptually stuck on an :inline which intentionally returns nil

Until there is an example of how this may matter, I can't see the problem.

for example, an inline meta for get could have:

(if (and (or (symbol? k) (scalar? k)) (nil? m)
  nil
  `(clojure.lang.RT/get ~m ~k))
Then other places that see this nil can keep folding it. In that way, for example, you won't need the nil case for get-in This is a special case of constant folding can can't access

Other places can handle (do) as foldable/droppable value.

So every place will need to special case handling this specific form instead of having an API to signal inlining can't be done

Ackchyually, inlines, like macros, expand from outside inwards. So if you want to implement the thing you talk about (recursive expansion and handling) you would have to recurse by yourself, cosplaying the compiler. And then handle the return values of the inlined functions. And there you would need to have special treatment for whatever API for "inlining impossible" Clojure ends up shipping.

🤔 1

For ClojureDart we have a slightly different design with :inline-pred returning false/true/fn (when fn returned it's used as inlining fn). Thus an inline can still return a proper nil.

Re: recursive expansion. in CLJD you can tag a macro arg as :compiled in which case macro full expansion for this argument happens before the macro call. The value handled to the macro is an object providing information (inferred type, free variables, presence of open forms such as recur etc)

That's what I would have liked if I could choose

an inliner returns a form, which can be 'nil (the symbol nil) But remember this replaces an invocation, it is not a general macro system, so actually turning into no code at all is unlikely to work in all places where a call might appear

👍 1

Was ! not a convention for unsafe operations? Now it is planned in Clojure 1.13 in destructuring for different purposes. Wondering why.

'unsafe' might not be the right word (unless it's explicitly listed somewhere I'm unaware of), but I do associate the ! with "more attention is required/more liable to throw an exception if something's wrong", which I think fits their usage in 1.13

👍 1

Anybody remembers clojure.core/io!? 😄

if you mean unsafe as in "this may crash", then the ! is fully justified ;)

😆 1

I've been interpreting ! as "caution" ever since volatile! was introduced. It has worked for me so far.

The FAQ says: https://clojure.org/guides/faq#qmark_bang "a trailing ! to denote a function with side-effects" which throwing an exception certainly is 🙂

I would also recommend caution when taking that style guide as gospel, it looks very polished and official, but I think the odds of rich having read it are very very low, and even if he did read it, would he agree with it? so I would not expect him to feel constrained by it in any way when making naming decisions.

There are also many functions in the wild, and in clojure.core that side effect in some way or another and don't come with a !

Re: Rich and the "community style guide" -- yup, totally agree: it's much more of a fiction manufactured by the community than anything even vaguely official (and I say that as one of the editors of that style guide).

Now I understand the reasoning. :keys! is used for its effects, while :keys not.

But I don't agree. Normally I would not use :keys! for its effects. I would use it, because I want a binding. If the binding fails, it is just a programming error like million others, but not an effect.

I think, :keys! will quickly become the new default everywhere. At least for me. I guess in 90% of the cases you want, what you bind. Clojure code in future will be full of :keys! everywhere. In my opinion it is not nice, that a standard language feature has an !.

For me the ! was a very practicable way to see everything, which has a side effect. You open a piece of code, and you see where the side effects are. Now we have an inflation of ! symbols for everything, which would need some sort of attention. Exceptions are not the same pain point as side effects. That's why I personally have sympathy for ! as a marker for side effects.

If you use :keys! over :keys, you are by definition using it for its side-effect (of throwing an exception).

If you use :keys and a value is not passed, you can either give it a default (via :or) or check it is not nil explicitly in your code, or use contains? on the :as map. If you use :keys! and a value is not passed, your function does not get control.

Wrote this ten hours ago but apparently I didn't press enter! I don't think it will become the default. After all, we didn't have assert on the presence of keys everywhere before, so I think the vast majority of cases will stay :keys, just like they are today. At work, we switched from :keys + assertions to :keys! in the places where we already had assertions. Will we use :keys! in more places, going forward? Yes, in places where we would otherwise have added assertions 🙂

There are only so many characters. So sometimes context will have to come into play. Just like for words and names.