-
-
Save cjfrisz/7594736 to your computer and use it in GitHub Desktop.
user=> (symbol "1") | |
1 | |
user=> (number? (symbol "1")) | |
false | |
user=> (symbol? (symbol "1")) | |
true | |
user=> (= (symbol "1") 1) | |
false | |
user=> (= (symbol "1") '1) | |
false |
(I'm torn between laughing at someone explaining how quote works to Chris and discussing why cemerick's answer doesn't address the underlying philosophical problem that Chris is trying to bring up.)
If there is basic type tagging in Clojure (which is common in lisps), then numbers should have a different type tag than symbols, which means that (symbol "1")
should be a symbol build off of the unicode/ascii representation of 1
. Thankfully, Clojure does this, but not without being horrifically misleading. Consider this in Clojure:
user=> (symbol "1")
1
user=> '1
1
If we try this in another lisp (like Petite), we get a (more explanatory) result:
> (string->symbol "1")
\x31;
> '1
1
Similarly, if we try this in Racket, we get another result indicating the difference.
> (string->symbol "1")
'|1|
> '1
1
I'm with CJ Frisz on this: that's some serious shenanigans. The pretty-printer, while trying to be "nice", is actually being incredibly opaque here. By pretty-printing that not-quite-one as a one, it's unclear that the type tag is unexpected. And in any case, why doesn't string->symbol
recognize that it's just a number and return the expected, correctly-tagged version?
Well, it's a public exchange on a Clojure FAQ (at least, as much as FAQs exist re: the details of read and eval semantics), so I write so that as many people can understand as possible. Seems like a good salve to twitter convos. Of course, no offense intended.
I'll quickly concede that it'd be nice if Clojure printed ambiguous symbols with pipes, something that's come up as a potential language enhancement a couple of times. It's never risen to the level of must-have. shrug
Anyway, not sure what you mean by "recognize that it's just a number and return the correctly-tagged version". string->symbol
, like symbol
in Clojure, should return a symbol all the time, regardless of the contents you provide it, no?
I've spent about a day thinking about this, and I can't come up with a definitive answer.
I think it might be material to the discussion that Clojure symbols are much heavier-weight than Scheme/Racket symbols. Under the covers, each Clojure symbol is a distinct Java object with a name string and (optionally) a namespace string. On the other hand, the Scheme standard specifies that all instances of a symbol with a given name be exactly the same symbol. To illustrate:
user=> (= 'a 'a) ; value equality
true
user=> (identical? 'a 'a) ; pointer equality
false
> (eqv? 'a 'a) ; value equality
#t
> (eq? 'a 'a) ; pointer equality
#t
As an aside, this might make Clojure symbols look crazy from a Schemer's point of view, but it's important to note that the notion of symbols in Scheme maps more closely onto Clojure keywords. For instance:
user=> (= :a :a)
true
user=> (identical? :a :a)
true
In the end, I think the answer is either that the Clojure way of printing symbols is entangled with the underlying representation, which from what I can tell is necessary for avoiding some of the pitfalls of not having a hygienic macro system, or else Rich Hickey didn't think direct usage of symbols was common or important enough (as in Scheme/Racket) to warrant extra work for sanitizing a leading number. Perhaps this tweet indicates the latter...
I think you have it just right, @cjfrisz. The only quibble I'd have is that if "heavyweight" was meant to refer to the relative size of each keyword / symbol, then keywords are actually the weightier of the two; each clojure.lang.Keyword
instance contains a corresponding symbol, plus some hash stuffs. Of course, the interning of keywords you mention means that they might be faster to obtain if they're already in the pool.
(Cemerick, that wasn't meant as a slight against you, because I've seen a lot of users who need the exact explanation you just gave. I found the situation genuinely amusing, not offensive.)
I agree with @cjfrisz that, given Clojure considers itself a Lisp, it seems unexpected that symbols act so differently than in most other modern Lisps (from clisp to racket), and I think this is a pairing of printer ambiguity (which may be hectic to fix) and unexpected symbol behavior.
Is this a bug or feature?
FWIW, symbols are interned in most Lisp dialects I've used.
'1
isn't a symbol, it's still a number:quote
(a.k.a.'
) prevents evaluation of the enclosed form, but that just means you're going to be left with that form, nothing more.You might be confused because:
…but that is so because
'a
is actually(quote a)
;a
is already a symbol,quote
just prevents it from being evaluated within the current context.FWIW, if you're doing e.g. symbolic manipulation of some sort,
1
is a perfectly acceptable "symbol" for the number1
; even better, since it actually is the number1
! :-)