Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uninterned symbols in Common Lisp

Several times I came across the notion of uninterned symbols, but I am not entirely clear about what they are.

Is there a way to intern a symbol created with (make-symbol)?
Can I assign a value to a symbol without interning it?
Is it possible to rename a symbol (interned or uninterned)?
What else can one do with an uninterned symbol?

Update:
What is happening with symbols in this piece of code?

CL-USER> (defun func ()
           (let ((var 'sym))
             (print (find-symbol "sym"))
             (print var)))
FUNC
CL-USER> (func)

NIL 
SYM 
SYM

My incorrect understanding is:
1. find-symbol prints nil, so the symbol is not intered
2. var prints sym without #: in the beginning which means it is interned

like image 919
sabof Avatar asked Dec 02 '11 16:12

sabof


1 Answers

Uninterned symbols are mostly used as names or designators to avoid cluttering packages, or for related tasks.

For example:

T1> (find-symbol "T2")
NIL
NIL
T1> (find-symbol "T3")
NIL
NIL
T1> (defpackage t2)
#<Package "T2">
T1> (defpackage #:t3)
#<Package "T3">    
T1> (find-symbol "T2")
T2
:INTERNAL
T1> (find-symbol "T3")
NIL
NIL

As you can see, using t2 in the first defpackage form interns it in package t1, while using #:t3 in the second defpackage avoids this. This is possible, because defpackage takes a string designator as its first element, and a symbol doesn't need to be interned to function as a designator.

These and related situations are where uninterned symbols are mostly used deliberately. You could also avoid polluting the package by using a string or a keyword, but in the first case, there may be problems with people using other than the default readtable-case, and in the second case you would pollute the keyword package, which some people care about. (There are different opinions as to whether this really is such a bad thing or not.)

Then, there are situations where a symbol loses its home-package (by uninterning, for example) and becomes at least apparently uninterned. (It may still be interned in another package.)

T1> (defparameter *t2* (find-symbol "T2"))
*T2*
T1> (import *t2* "T3")
T
T1> (symbol-package *t2*)
#<Package "T1">
T1> (unintern *t2*)
T
T1> (find-symbol "T2")
NIL
NIL
T1> (symbol-package *t2*)
NIL
T1> *t2*
#:T2
T1> (find-symbol "T2" "T3")
#:T2
:INTERNAL
T1> (unintern *t2* "T3")
T
T1> (import *t2* "T3")
T
T1> *t2*
T3::T2
T1> (symbol-package *t2*)
#<Package "T3">

So, the answer to

Is there a way to intern a symbol created with (make-symbol)?

is yes:

T1> (import (make-symbol "T4"))
T
T1> (find-symbol "T4")
T4
:INTERNAL

Can I assign a value to a symbol without interning it?

Yes, while you're losing the property that it can be uniquely identified by its name and packagage, you can still use its value slot, plist, etc.:

T1> (let ((symbol '#:t5))
      (setf (symbol-value symbol) 1)
      (setf (get symbol :foo) :bar)
      (setf (symbol-function symbol) (lambda ()))
      (values (symbol-value symbol)
              (get symbol :foo)
              (symbol-function symbol)))
1
:BAR
#<Anonymous Function #xC829036>

Is it possible to rename a symbol (interned or uninterned)?

The consequences of modifying a symbol's name are undefined.

What else can one do with an uninterned symbol?

I really think they're mostly used as designators in package definitions, but to the general answer would be: They can be useful in situations where you want to name things without using hardcoded strings and don't want to pollute any package.

like image 152
danlei Avatar answered Sep 25 '22 07:09

danlei