Welcome! Please see the About page for a little more info on how this works.

0 votes
in Errors by

I'm implementing a small Lisp interpreter, which led me to discover this bug in the implementation of case:

(case "s"
  'quote "quote"
  "default")

;; Syntax error macroexpanding case at (org:localhost:56082(clj)*:131:16).
;; Duplicate case test constant: quote

I thought this might be a good workaround:

(case 'quote
  (symbol "quote") "quote"
  "default")
;; => "default"

This doesn't work, it returns "default".

Strangely, even though (symbol quote) would be invalid, since quote is not bound, THIS does "work" by returning "quote":

(case 'quote
  (symbol quote) "quote"
  "default")
;; => "quote"

Very weird. And look at this. Let's try a case of 'face. What will it return?

(case 'quote
  'face "face"
  "default")
;; => "face"

It matches 'quote!

Actually anything quoted matches:

(case 'quote
  (quote 123) "123"
  "default")
;; => "123"

Hopefully this will be enough for this to make sense to someone with knowledge of case's macroexpansion.

Cheers!

1 Answer

+1 vote
by
selected by
 
Best answer

This is the expected behavior per the docstring, not a bug.
'foo => (quote foo)
That happens in the reader and per the case docstring you can have (constant constant constant...) so this is the pair of constant symbols quote and foo.

That's why your case on the (evaluated) expression 'quote matches 'face because it's the pair of constant expressions quote and face.

Similarly, (symbol quote) is the pair of constant expressions symbol and quote (and, again, your test expression matches.

From the docstring: "The test-constants are not evaluated. They must be compile-time literals, and need not be quoted."

In case it is not clear from that, the reason 'quote is not legal is because the reader expands that to (quote quote) and now you have a duplicate constant expression.

by
Excellent, thanks for the wonderful explanation!
by
Not part of the original question, but, importantly: be aware that ClojureScript evaluates const symbols in `case` (alluded to in "Differences from Clojure" https://clojurescript.org/about/differences).
...