Symbols can look like keywords

~ # clojure
Clojure 1.10.1
user=> #{(symbol ":?") (keyword "?")}
#{:? :?}
user=> (map type #{(symbol ":?") (keyword "?")})
(clojure.lang.Symbol clojure.lang.Keyword)
user=> (apply = #{(symbol ":?") (keyword "?")})
false
user=>

They certainly can, if you make them look like each other. I doubt anyone will be surprised if they hear the suggestion “don’t do that – that way lies madness”.

3 Likes

That arose at work in a large map composed from a spreadsheet,
and puzzled someone who is (quickly) learning Clojure.

Calling symbol or keyword on arbitrary strings can easily lead to things like this. If you have a choice, considering keeping them as strings instead. Strings can be used as keys in Clojure maps, just fine, and round-trip well between writing them out as data, and reading them back, using the appropriate Clojure code for printing them (which I don’t keep off the top of my header, but might be pr).

Historical context: This question was raised in 2008 and cataloged in the Clojure Jira as issue No.17: https://clojure.atlassian.net/browse/CLJ-17 “Validate in (keyword s) and (symbol s)”. In the end, a way was not found to do it without causing slowdowns disproportionate to the benefit.

Thanks guys.
I don’t think this is a problem to be fixed.
It’s just a thing that beginners can stumble on.

Here’s a related thing that I remember having lost a few hours struggling with in the early days.

(keyword nil "b/c")

The example might look silly but again it came from mechanically constructing keywords from data. It took me a while to work out why the result wouldn’t equal :b/c that I typed in

Thanks. I have not debugged that one … yet.