Fork me on GitHub
#clojure
<
2024-02-02
>
roninhacker05:02:23

TIL:

user> (type :kw)
clojure.lang.Keyword
user> (case (type :kw) clojure.lang.Keyword 3)
Execution error (IllegalArgumentException) at user/eval15257 (REPL:716).
No matching clause: class clojure.lang.Keyword

roninhacker05:02:31

user> (doc case) ------------------------- clojure.core/case ([e & clauses]) Macro Takes an expression, and a set of clauses. Each clause can take the form of either: test-constant result-expr (test-constant1 ... test-constantN) result-expr The test-constants are not evaluated. They must be compile-time literals, and need not be quoted. If the expression is equal to a test-constant, the corresponding result-expr is returned. A single default expression can follow the clauses, and its value will be returned if no clause matches. If no default expression is provided and no clause matches, an IllegalArgumentException is thrown. Unlike cond and condp, case does a constant-time dispatch, the clauses are not considered sequentially. All manner of constant expressions are acceptable in case, including numbers, strings, symbols, keywords, and (Clojure) composites thereof. Note that since lists are used to group multiple constants that map to the same expression, a vector can be used to match a list if needed. The test-constants need not be all of the same type. nil user>

Bob B05:02:58

ahh, the good old symbol vs class "clash"

Bob B06:02:34

paradoxically, I feel like it becomes a little bit clearer what's happening when using what, at first, seems to be an even more baffling example:

(case clojure.lang.Keyword 
  clojure.lang.Keyword 3)
No matching clause: class clojure.lang.Keyword

‼️ 1
roninhacker06:02:12

I think this has been what's getting me:

They must be compile-time literals

roninhacker06:02:46

lots of weird stuff like:

(case '(1 2) (1 2) 3)
Execution error (IllegalArgumentException) at user/eval15343 (REPL:818).
No matching clause: (1 2)
user> 

roninhacker06:02:23

oh wait lol that does work if you quote both, hmm

roninhacker06:02:35

user> (case '(1 2) '(1 2) 3)
3

Bob B06:02:26

yeah... since the argument to case is evaluated, clojure.lang.Keyword is a class, but as a case, it's not evaluated (the compile-time literals part), so it's a symbol

roninhacker06:02:29

(let [v '(1)]
      (case v
          '(1) \a
          '(2) \b))
Syntax error macroexpanding case at (*cider-repl projects/lrsql:localhost:40521(clj)*:835:9).
Duplicate case test constant: quote

Bob B06:02:16

right, because '(1) reads as (quote (1), the actual case will match the symbol quote or a list of 1

Bob B06:02:47

(case 'quote
  '(1 2) 3)
=> 3

parens 2
roninhacker06:02:56

ok that's weird

Bob B06:02:10

it can probably qualify for "unintuitive", and I think it's one of those things that's easy to trip over, but good to have when you need it

👍 1
hifumi12309:02:04

A similar issue occurs with Java enums, so there are valid reasons to write (condp = val ...) instead of (case val ...)

🎉 1
phill12:02:16

Beware that ClojureScript's case may evaluate constant literals! In practice, if the code might wind up in cljc, avoid symbols in case.

Miķelis Vindavs09:02:27

Hello. Could anyone help me understand what’s going on here? Is accessing static class fields with function call syntax an undocumented feature?

user=> java.text.BreakIterator/DONE
-1
user=> (java.text.BreakIterator/DONE)
-1
user=> (ifn? java.text.BreakIterator/DONE)
false
user=> (let [x java.text.BreakIterator] (x))
Execution error (ClassCastException) at user/eval144 (REPL:1).
user=> ((java.text.BreakIterator/DONE))
Execution error (ClassCastException) at user/eval146 (REPL:1).
java.text.BreakIterator.DONE is a static final int

thheller09:02:33

yes, an undocumented feature which I believe is going to be removed soon

thheller09:02:09

can't remember where I read that though, so might be misremembering

thheller09:02:19

but there are some changes to interop forms coming in 1.12

Miķelis Vindavs09:02:25

Nice, thanks Ben

Ben Lieberman09:02:36

You're welcome

mloughlin11:02:27

Does anyone know of any further info (blog posts etc) on how spec's instrumentation is implemented?