Difference between setf, setq, ....

Hi Steve,

As the resident Nyquist/Lisp guru, could you please explain the differences between the following please.
The main reference is not that clear.

set, setf, setq and psetq

TIA.

BTW

Just found your Lisp code to read the output from a tachometer, very handy in that it finds frequency and times.
Could have other possible uses, busy studying it.

For standard XLISP functions, the XLISP manual is the best reference.
I would highly recommend bookmarking the “Language Reference” page: https://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-ref/xlisp-ref-index.htm

SET
Sets a symbol to a value.

An important consideration is that when Nyquist (LISP) sees a symbol, it will try to evaluate it.
For example, if “mysymbol” = 42, and you print:

(print mysymbol)

Then Nyquist will print 42.

Now consider:

(set mysymbol 42)

This returns an error (try it in the Nyquist Prompt with the Debug button):

error: unbound variable - MYSYMBOL
if continued: try evaluating symbol again
1>

The problem here is that Nyquist has tried to evaluate “mysymbol”, but “mysymbol” has not yet been defined. (Nyquist does not declare variables).

Somehow we need to tell Nyquist “Don’t evaluate this”. Something like:

(set (do-not-evaluate-this mysymbol) 42)

As you’ve probably guessed, I just made up “do-not-evaluate-this” :wink:
The way that Nyquist / LISP actually does it is with QUOTE

(set (quote mysymbol) 42)
(print mysymbol)  ;prints 42

or the more common short version:

(set 'mysymbol 42)
(print mysymbol)  ;prints 42

“(SET (QUOTE …” is such a common pair of commands, that there is an abbreviated form: SETQ
These statements are equivalent to each other:

(set (quote mysymbol) 42)
(set 'mysymbol 42)
(setq mysymbol 42)

PSETQ

Consider the case where you are initialising a bunch of variables:

(setq a 12)
(setq b 7)
(setq c 0.5)
(setq d "a string")

This will set the values of the symbols A, B, C, and D sequentially.
In this case, because none of the symbol values depend on any other symbol value, the order of these initialisations is unimportant.
We could do this, and the result is exactly the same:

(setq d "a string")
(setq c 0.5)
(setq b 7)
(setq a 12)

In fact, we don’t really need to set them sequentially. We could set them all at the same time, in parallel.
To do that, we would need a command that means “parallel set quoted”, and that is what the command PSETQ means.

(psetq a 12
       b 7
       c 0.5
       d "a string")

or simply:

(psetq a 12 b 7 c 0.5 d "a string")

Try this in the Nyquist Prompt with the Debug button:

(psetq a 12 b 7 c 0.5 d "a string")
(print a)
(print b)
(print c)
(print d)

SETF
This is similar to SETQ, but it is more powerful.

Like SETQ, you can use SETF to set the value of a symbol (without evaluating the symbol).
These two lines are equivalent:

(setq mysymbol 42)
(setf mysymbol 42)

The difference is that SETF (which is short for “set field”) can be used with more than just symbols.

A couple of examples:

Array elements:

(setf ar (vector "A" "B" "C" "D")) ;An array with four elements.
(setf (aref ar 2) 42) ;set the value of array element with index 2.
(print ar)  ; prints #("A" "B" 42 "D")

Note that this will not work with SETQ, because (aref ar 2) is not a symbol. SETQ only works with symbols.

List elements:

(setf ls (list "A" "B" "C" "D")) ;A list with four elements.
(setf (nth 2 ls) 42) ;set the value of array element with index 2.
(format nil "~a" ls)  ; prints (A B 42 D)

Side note: I used FORMAT here rather than PRINT because PRINT returns the list, and Audacity doesn’t know what to do with a list unless it’s a “label list”. FORMAT returns a string, which Audacity can display.


Q. Why use SETQ at all if we can use SETF instead?

A. Good question, I’m glad you asked :wink:
Yes we can use SETF instead of SETQ, and some LISP programmers do that. On the other hand, some LISP programmers prefer to use SETQ when they are setting the value of a symbol, so that it is clear that “the thing” being set is just an ordinary symbol.

While there are plenty of situations where we must use SETF rather than SETQ (such as array elements, list element, …) I don’t think there are any cases where we must use SETQ rather than SETF.

I’ve been trying to think of cases where SETQ may make the code a bit clearer.
One example I came up with is if a symbol has both a symbolic value, and a functional value.

(defun foo (x) (* x 2))         ;define function FOO
(setf (symbol-value 'foo) 42)   ;set the symbolic value of FOO

; Set the functional value of BAR to the functional value of FOO.
; We must use SETF here because "(symbol-function 'bar)" is not a symbol.
(setf (symbol-function 'bar) (symbol-function 'foo))

; Set the value of BAR to the symbolic value of FOO.
; We could use SETF here, but using SETQ it is perhaps
; clearer that we are only dealing with BAR as a symbol.
(setq bar foo)

(print (bar 3)) ;prints 6
(print bar)     ;prints 42

Wow, perfect explanation and examples, thanks very much Steve, appreciate your time and expertise.

I’ve saved this whole thread as a pdf for reference.