Differences between Sharpsign Colon and Gensym
Asked Answered
H

2

8

I've just been reading up on the sharpsign colon reader macro and it sounded like it had a very similar effect to gensym

Sharpsign Colon: "introduces an uninterned symbol"

Gensym: "Creates and returns a fresh, uninterned symbol"

So a simple test

CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {1002FF77D3}>.
CL-USER> (defparameter #:dave 1)
#:DAVE
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {100324B493}>.

Cool so that fails as it should.

Now for the macro test

(defmacro test (x)
  (let ((blah '#:jim))
    `(let ((,blah ,x))
       (print ,blah))))

CL-USER> (test 10)

10 
10
CL-USER>

Sweet so it can be used like in a gensym kind of way.

To me this looks cleaner than gensym with an apparently identical result. I'm sure I'm missing a vital detail so my question is, What it it?

Humiliating answered 2/2, 2015 at 9:35 Comment(0)
S
6

GENSYM is like MAKE-SYMBOL. The difference is that GENSYM supports fancy naming by counting up -> thus symbols kind of have unique names, which makes debugging a bit easier when having gensyms for example in macro expansions.

#:foo is a notation for the reader.

So you have a function which creates these and a literal notation. Note that, when *print-circle* is true, some kind of identity maybe preserved in s-expressions: #(#1=#:FOO #1#).

Generally this is similar to (a . b) and (cons 'a 'b), #(a b) and (vector 'a 'b)... One is literal data and the other one is a form which will create ('cons') fresh objects.

If you look at your macro, the main problem is that nested usage of it could cause problems. Both lexically or dynamically.

  • lexically it could be the same variable, which is rebound.

  • dynamically, if it is a special variable it could also be rebound

Using a generated symbol at macro expansion time would make sure that different and expanded code would not share bindings.

Suck answered 2/2, 2015 at 11:9 Comment(1)
Oh yeah, I hadn't spent any time thinking of the capture implications, which obviously the whole point..woops! Thanks for thisHumiliating
T
9

Every time the macro is expanded, it will use the same symbol.

(defmacro foo () `(quote #:x))
(defmacro bar () `(quote ,(gensym)))

(eq (foo) (foo)) => t
(eq (bar) (bar)) => nil

Gensym will create a new symbol every time it is evaluated, but sharp colon will only create a new symbol when it is read.

While using sharp colon is unlikely to cause problems, there are a couple rare cases where using it would lead to nearly impossible to find bugs. It is better to be safe to begin with by always using gensym.

If you want to use something like sharp colon, you should look at the defmacro! macro from Let Over Lambda.

Trudge answered 2/2, 2015 at 11:10 Comment(1)
Nailed it, I was being a dummy for not thinking of capture. I have even read let over lambda, so I was really being an airhead today heheHumiliating
S
6

GENSYM is like MAKE-SYMBOL. The difference is that GENSYM supports fancy naming by counting up -> thus symbols kind of have unique names, which makes debugging a bit easier when having gensyms for example in macro expansions.

#:foo is a notation for the reader.

So you have a function which creates these and a literal notation. Note that, when *print-circle* is true, some kind of identity maybe preserved in s-expressions: #(#1=#:FOO #1#).

Generally this is similar to (a . b) and (cons 'a 'b), #(a b) and (vector 'a 'b)... One is literal data and the other one is a form which will create ('cons') fresh objects.

If you look at your macro, the main problem is that nested usage of it could cause problems. Both lexically or dynamically.

  • lexically it could be the same variable, which is rebound.

  • dynamically, if it is a special variable it could also be rebound

Using a generated symbol at macro expansion time would make sure that different and expanded code would not share bindings.

Suck answered 2/2, 2015 at 11:9 Comment(1)
Oh yeah, I hadn't spent any time thinking of the capture implications, which obviously the whole point..woops! Thanks for thisHumiliating

© 2022 - 2024 — McMap. All rights reserved.