17

Here's the thing: I don't "get" setf-expanders and would like to learn how they work.

I need to learn how they work because I've got a problem which seems like a typical example for why you should learn setf-expanders, the problem is as follows:

(defparameter some-array (make-array 10))

(defun arr-index (index-string)
  (aref some-array (parse-integer index-string))

(setf (arr-index "2") 7) ;; Error: undefined function (setf arr-index)

How do I write a proper setf-expander for ARR-INDEX?

Johan
  • 605
  • 5
  • 16

2 Answers2

23
(defun (setf arr-index) (new-value index-string)
  (setf (aref some-array (parse-integer index-string))
        new-value))

In Common Lisp a function name can not only be a symbol, but also a list of two symbols with SETF as the first symbol. See above. DEFUN thus can define SETF functions. The name of the function is (setf arr-index).

A setf function can be used in a place form: CLHS: Other compound forms as places.

The new value is the first argument then.

CL-USER 15 > some-array
#(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)

CL-USER 16 > (setf (arr-index "2") 7)
7

CL-USER 17 > some-array
#(NIL NIL 7 NIL NIL NIL NIL NIL NIL NIL)
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • 2
    I couldn't find this in the CLHS, where is it? – Nowhere man Dec 10 '15 at 11:07
  • 1
    @Nowhereman: http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_name – Rainer Joswig Dec 10 '15 at 11:34
  • I had seen it in the glossary, but where is it explained how to define a setf function with (defun (setf foo)...)? – Nowhere man Dec 10 '15 at 19:17
  • @Nowhereman: there is no direct explanation. But it's defined that a setf function can be used in a place form and that `defun` can define functions with a setf name. – Rainer Joswig Dec 10 '15 at 19:35
  • 2
    `#'(setf arr-index)` is now a function that you can call. It's what the setf macro expands to, that is `(funcall #'(setf arr-index) new-value index-string)`. – mihai Jan 18 '19 at 13:03
  • 1
    In addition to the glossary definition cited above, this is discussed in CLHS 5.1.2.9: http://www.lispworks.com/documentation/HyperSpec/Body/05_abi.htm – massysett Feb 11 '23 at 21:40
6

Rainer's answer is spot on. Before ANSI Common Lisp, it was necessary to use defsetf to define an expander for simple places that could be set with a simple function call. setf functions like (setf arr-index) came into the language with CLOS and simplify a lot of things. In particular, setf functions can be generic.

Tim
  • 502
  • 4
  • 10