Page 1 of 2

Question about intern and symbols

Posted: Sun Apr 26, 2009 9:16 pm
by jrigler
I want to generate and initialize a symbol dynamically in SBCL. If given I string "TEST", I want to evaluate to:

(setf TEST 5)

so far I am able to run:

(intern "TEST")
TEST

but this doesn't work:

(setf (intern "TEST") 5)
The function (SETF INTERN) is undefined.

I did however just find a 'historically important' function that works just fine:
(set (intern "TEST") 5)
5
CL-USER>TEST
5

So what's the story with setf, am I just trying to misuse lisp?

Re: Question about intern and symbols

Posted: Mon Apr 27, 2009 10:14 am
by Harleqin
SETF is serious magic. It can set many places, for example hash-table entries, array elements, or just arbitrary symbols. It is a macro that will analyze what kind of place its first (or rather, all odd) argument is, and call the appropriate setter function. If it doesn't know the kind of place, it cannot work.

So, you should read about what a place is to understand what SETF does. In manuals, you will often find a remark "setfable" with accessor functions, which indicates that this accessor function can be used as a place for SETF, as in:

Code: Select all

(setf (gethash key hash-table) value)
For your intentions, SET seems to be the right choice. If you want to access dynamic variables, SYMBOL-VALUE is setfable (but this only works for dynamic variables).

Re: Question about intern and symbols

Posted: Mon Apr 27, 2009 10:29 am
by ramarren
Harleqin wrote:For your intentions, SET seems to be the right choice. If you want to access dynamic variables, SYMBOL-VALUE is setfable (but this only works for dynamic variables).
In fact, the standard says:

Code: Select all

(set symbol value) ==  (setf (symbol-value symbol) value)
And you can't really do anything to lexical variables at runtime by name, because by then names might no longer exists, which leaves only dynamic variables.

Anyway, I believe this is one of those cases where asking "why do you want to do that" is warranted. In almost all cases for associating strings or symbols with values dynamically hash tables are better.

Re: Question about intern and symbols

Posted: Mon Apr 27, 2009 3:05 pm
by jrigler
Ramarren wrote: Anyway, I believe this is one of those cases where asking "why do you want to do that" is warranted. In almost all cases for associating strings or symbols with values dynamically hash tables are better.
I was interested in making a list of symbols that would be easy to manipulate as a list and yet could have all of the cool features of symbols. I had been looking at Paul Grahams Double-Linked List Structure and thought it was cool, but didn't like that it seemed like I would have to reinvent alot of functionality that was already in normal lists. I don't want to do 'wierd things' though and had strongly considered looking at hashes. I am interested in making a general html menu structure or class that can handle many sub-menus when appropriate yet also know given a page name where it fits in the structure. I have read that plists are both very cool (Graham) and are somewhat archaic (Steele). In this snippet below, if you know that a current page is 'MAIN, then without searching, you also know that it is a member of TOPMENU. I had envisioned only using these symbols in a special HTML package, so as to be isolated and can't really imagine over 50 of these symbols loaded up at any given time.

(setf TOPMENU (list 'MAIN 'GALLERY 'ABOUT 'CONTACT))
(setf MAIN(list 'MAIN_SUB1 'MAIN_SUB2))
(setf (get 'MAIN 'URL) "main.html")
(setf (get 'MAIN 'TITLE) "Main Page of Website")
(setf (get 'MAIN 'PARENT) 'TOPMENU)

Maybe this will just lead to inflexibility and more wierdness down the road and I should go back to looking at a combination of structures or classes and hash tables.

Thanks, hope this makes (some) sense, if you think this is odd, you should see what I was doing to php ;-)

Re: Question about intern and symbols

Posted: Mon Apr 27, 2009 10:07 pm
by ramarren
Paul Graham has a very specific style, since he doesn't like large part of Common Lisp, like LOOP or CLOS, so following his advice will often lead to Scheme-like code. There is nothing fundamentally wrong with that, but this is relatively uncommon among programs written in Common Lisp, and might be considered archaic or unidiomatic. Fortunately, there is no such thing as unified Lisp community, so it doesn't matter that much.

Symbol plists also are, obviously, global values, and all problems with global variables apply. For the problem you describe I would just use CLOS classes and hashtables, especially if the structure is well defined.

Re: Question about intern and symbols

Posted: Tue Apr 28, 2009 5:29 am
by Harleqin
Ramarren wrote: Symbol plists also are, obviously, global values, and all problems with global variables apply.
That's an interesting question. In Common Lisp, "global" variables are special, i.e. dynamic, not really global. It may at first seem the same, but this mediates the problems associated with global variables to some extent. Does this also apply to symbol plists? Can you dynamically handle symbol plists?

Re: Question about intern and symbols

Posted: Tue Apr 28, 2009 10:13 am
by findinglisp
Harleqin wrote:
Ramarren wrote: Symbol plists also are, obviously, global values, and all problems with global variables apply.
That's an interesting question. In Common Lisp, "global" variables are special, i.e. dynamic, not really global. It may at first seem the same, but this mediates the problems associated with global variables to some extent. Does this also apply to symbol plists? Can you dynamically handle symbol plists?
No, not automatically. Symbol plists are a separate "attribute" of the symbol, so to speak. They are not affected by the symbol's value. You could, of course, write macros to save/restore the plist values and create the same effect, but you'd have to do it by changing the plist value manually, not simply using LET.

Re: Question about intern and symbols

Posted: Wed Apr 29, 2009 4:39 am
by Harleqin
Thanks, Dave, that cleared up a lot for me.

Of course, this begs some new questions. Is there a tutorial somewhere that explains the inner workings of dynamic and lexical variables with respect to CL's symbols?

Re: Question about intern and symbols

Posted: Wed Apr 29, 2009 7:04 pm
by findinglisp
Harleqin wrote:Thanks, Dave, that cleared up a lot for me.

Of course, this begs some new questions. Is there a tutorial somewhere that explains the inner workings of dynamic and lexical variables with respect to CL's symbols?
Not that I can think of off-hand. Here's the shortest tutorial that I can think of... ;)
  1. A symbol is a first-class object. When the reader interns a symbol, a full data structure corresponding to the symbol is created for it. This is in contrast to C where a variable name only exists in the source text and ceases to exist once the compiler has done its thing.
  2. A symbol has a few things associated with it, including a data value (stored in the value cell), a function value (stored in the function cell), and a plist. The data value is the top-level global value. The function value is the function or macro associated with that symbol (I believe most implementations use a property in the plist to indicate a macro vs. a function).
  3. You can access the value cell with SYMBOL-VALUE.
  4. You can access the function cell with SYMBOL-FUNCTION
  5. You can access the plist with SYMBOL-PLIST
  6. So, the global (special) value of a symbol is stored right "in" the symbol itself. When you bind a special variable, it reassigns the SYMBOL-VALUE using the strategy of storing away the old value in a temporary, setting the SYMBOL-VALUE to the new value, and then restoring the old value when the binding form (e.g. LET) exits.
  7. If bind a local variable, it essentially creates a mapping between the symbol and its value (mentally, imagine a hash table or an association list and you have the idea). The lexical binding is simply that, a binding between the symbol and its value. The value is not stored "in" the symbol itself as it is for the SYMBOL-VALUE.
  8. A compiler can optimize away all the information about lexical variable names during the course of its analysis. Since the storage for a lexical binding is not specified, the compiler is free to do anything it wants (it can store the values anywhere, in a block of memory associated with a closure, on the stack, on the heap, or whatever). The symbol used in the binding simply serves as a name in the source code, so the compiler is free to "forget" what symbol was bound to what in the actual object code emitted (think of this very much like C, where your binary may know that a value is stored at a given location, but has no knowledge of what you named that variable in your source code).
  9. This is not at all the case with globals. All symbols conceptually have a value cell. There are various ways to implement the storage, but the programmer is always able to access the value cell using SYMBOL-VALUE.
So, mentally, think of the value of a special variable as being "in" the symbol itself, part of the data structure that defines the first-class symbol object. Think of a lexical binding as simply an association between a symbol (a first-class object) and its value (another first-class object).

Re: Question about intern and symbols

Posted: Wed Apr 29, 2009 8:08 pm
by Harleqin
Very nice!

So:

Code: Select all

CL-USER> (defparameter *test* 1)
*TEST*
CL-USER> *test*
1
CL-USER> (symbol-value '*test*)
1
CL-USER> (let ((*test* 2))
           (symbol-value '*test*))
2
CL-USER> (let ((*test* 2))
           (setf (symbol-value '*test*) 3)
           (print *test*)
           (print (symbol-value '*test*)))
3 
3 3
CL-USER> (symbol-value '*test*)
1
CL-USER> (setf (symbol-value '*test*) 4)
4
CL-USER> (symbol-value '*test*)
4
CL-USER> *test*
4