Difference between `set`, `setq`, and `setf` in Common Lisp?
Asked Answered
B

6

202

What is the difference between "set", "setq", and "setf" in Common Lisp?

Burny answered 15/5, 2009 at 16:0 Comment(1)
The behavior of these is answered pretty well in the answers, but the accepted answer has a possibly mistaken etymology for the "f" in "setf". The answer to What does the f in setf stand for? says that it's for "function", and provides references to back it up.Arbitrate
M
198

Originally, in Lisp, there were no lexical variables -- only dynamic ones. And there was no SETQ or SETF, just the SET function.

What is now written as:

(setf (symbol-value '*foo*) 42)

was written as:

(set (quote *foo*) 42)

which was eventually abbreviavated to SETQ (SET Quoted):

(setq *foo* 42)

Then lexical variables happened, and SETQ came to be used for assignment to them too -- so it was no longer a simple wrapper around SET.

Later, someone invented SETF (SET Field) as a generic way of assigning values to data structures, to mirror the l-values of other languages:

x.car := 42;

would be written as

(setf (car x) 42)

For symmetry and generality, SETF also provided the functionality of SETQ. At this point it would have been correct to say that SETQ was a Low-level primitive, and SETF a high-level operation.

Then symbol macros happened. So that symbol macros could work transparently, it was realized that SETQ would have to act like SETF if the "variable" being assigned to was really a symbol macro:

(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))

foo => 42

(setq foo 13)

foo => 13

*hidden* => (13 . 42)

So we arrive in the present day: SET and SETQ are atrophied remains of older dialects, and will probably be booted from eventual successors of Common Lisp.

Markitamarkka answered 15/5, 2009 at 16:36 Comment(5)
Common Lisp always had lexical variables. You must be talking about some Lisp before Common Lisp.Jequirity
If SET and SETQ are to be booted from a Common Lisp successor, they will have to get some replacement. Their use in high-level code is limited, but low-level code (for example, the code SETF is implemented in) needs them.Exuviate
is there a reason you chose 'car' as a field instead of something that might get confused as the car function?Stoneman
This answer to What does the f in setf stand for? claims that the f actually stands for function, not field (or form, for that matter), and provides references, so while the setf for field makes some sense, it looks like it might not be correct.Arbitrate
Summary: set is a function. Thus it does not know the environment. set cannot see lexical variable. It can set only the symbol-value of its argument. setq is not "set quoted" any more. The fact that setq is a special form, not a macro shows that.Lindstrom
B
182
(set ls '(1 2 3 4)) => Error - ls has no value

(set 'ls '(1 2 3 4)) => OK

(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set

(setf ls '(1 2 3 4)) => OK - same as setq so far BUT

(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set
Brittney answered 25/9, 2009 at 6:57 Comment(12)
I find your answer to be more clear than the top voted one. Thanks a lot.Kavita
@Sourav, please NEVER use the letter "l" (ell) as a variable or symbol in example code. It is too hard to visually distinguish from the numeral 1.Aloysia
No, I still don't understand how (car ls) can be a l-value or not. Do you understand how to translate CLisp into C ? and how to write a CLisp interpreter ?Hankering
@user1952009 clisp is one Common Lisp implementation. If you want to refer to the language itself, CL the most used abbreviation.Finesse
@user1952009 To put it in C terms, car essentially dereferences the list "pointer", giving you a reference to the first item (first does the same thing). (setf (car ls) 10) might be written as *ls = 10; in C.Candlestand
@Candlestand so you are saying it is a L-value, so that (setf (car ls) 5)is the same as l->val = 5; in C. What about (setf (car (car (car ls))) 5) if say (setq ls '(((1))) ) ?Hankering
@user1952009 After (setq ls '(((1)))), (setf (car (car (car ls))) 5) is undefined behaviour, because the value of ls is constant (like modifying a string literal in C). After (setq ls (list (list (list 1)))), (setf (car (car (car ls))) 5) works just like ls->val->val->val = 5 in C.Stony
@Aloysia You probably need a better font. Try this: github.com/tonsky/FiraCodeIdiomorphic
@Stony not true, or at least implementation-dependentt. After (setq ls '(((1)))), (setf (car (car (car ls))) 5) works just fine, at least in CLisp and SBCL.Crotchety
@MarkReed I said that it was undefined behaviour, not that it doesn't work in any implementation. You cannot rely on it in portable Common Lisp.Stony
@MarkReed See the HyperSpec page for QUOTE: The consequences are undefined if literal objects (including quoted objects) are destructively modified.Stony
@MarkReed Here's an example where quoting works strangely on SBCL and CLISP: (defun abc-without (letter) (delete letter '(a b c))) (first (last (mapcar #'abc-without '(a b c)))). It returns (A), because when we call abc-without with the argument A and B, it calls delete with the same quoted (A B C) object from the def. If you replace the first '(a b c) with (list 'a 'b 'c) then it will return (A B) like you'd want. This difference in behaviour is not guaranteed by the standard. It's the same as how some C compilers on some platforms might let you modify string literals.Stony
E
24

You can use setf in place of set or setq but not vice versa since setf can also set the value of individual elements of a variable if the variable has individual elements. See the exaples below:

All four examples will assign the list (1, 2, 3) to the variable named foo.

(set (quote foo) (list 1 2 3))    ;foo => (1 2 3)
(1 2 3)

(set 'foo '(1 2 3))   ;foo => (1 2 3) same function, simpler expression
(1 2 3)

(setq foo '(1 2 3))   ;foo => (1 2 3) similar function, different syntax
(1 2 3)

(setf foo '(1 2 3))   ;foo => (1 2 3) more capable function
(1 2 3)

setf has the added capability of setting a member of the list in foo to a new value.

foo                   ;foo => (1 2 3) as defined above
(1 2 3)

(car foo)             ;the first item in foo is 1
1

(setf (car foo) 4)    ;set or setq will fail since (car foo) is not a symbol
4

foo                   ;the fist item in foo was set to 4 by setf
(4 2 3)

However, you can define a symbol macro that reprents a single item within foo

(define-symbol-macro foo-car (car foo))    ; assumes FOO => (1 2 3)
FOO-CAR

foo-car               ;foo-car is now a symbol for the 1st item in foo
1

(setq foo-car 4)      ;set or setq can set the symbol foo-car 
4

foo                   ;Lisp macros are so cool
(4 2 3)

You can use defvar if you have not already defined the variable and do not want to give it a value until later in your code.

(defvar foo2)
(define-symbol-macro foo-car (car foo2))
Elaterium answered 1/8, 2012 at 23:32 Comment(0)
F
22

setq is just like set with a quoted first arg -- (set 'foo '(bar baz)) is just like (setq foo '(bar baz)). setf, on the other hand, is subtle indeed -- it's like an "indirection". I suggest http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-16.html as a better way to get started understanding it than any answer here can give... in short, though, setf takes the first argument as a "reference", so that e.g. (aref myarray 3) will work (as the first arg to setf) to set an item inside an array.

Flin answered 15/5, 2009 at 16:18 Comment(1)
Makes most sense for the setq name. Easy to remember. Thanks.Kavita
J
19

One can think of SET and SETQ being low-level constructs.

  • SET can set the value of symbols.

  • SETQ can set the value of variables.

Then SETF is a macro, which provides many kinds of setting things: symbols, variables, array elements, instance slots, ...

For symbols and variables one can think as if SETF expands into SET and SETQ.

* (macroexpand '(setf (symbol-value 'a) 10))

(SET 'A 10)


* (macroexpand '(setf a 10))         

(SETQ A 10)

So SET and SETQ are used to implement some of the functionality of SETF, which is the more general construct. Some of the other answers tell you the slightly more complex story, when we take symbol macros into account.

Jequirity answered 8/8, 2013 at 9:25 Comment(0)
G
6

I would like to add to previous answers that setf is macro that call specific function depending on what was passed as its first argument. Compare results of macro expansion of setf with different types of arguments:

(macroexpand '(setf a 1))

(macroexpand '(setf (car (list 3 2 1)) 1))

(macroexpand '(setf (aref #(3 2 1) 0) 1))

For some types of arguments "setf function" will be called:

(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))
Gasbag answered 16/7, 2012 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.