In Practical Common Lisp chapter 17. Object Reorientation: Classes section Accessor Functions, I was finding it difficult understanding the way SETF is being extended.
The functions:
(defun (setf customer-name) (name account)
(setf (slot-value account 'customer-name) name))
bank-account class definition:
(defclass bank-account ()
((customer-name
:initarg :customer-name
:initform (error "Must supply a customer name."))
(balance
:initarg :balance
:initform 0)
(account-number
:initform (incf *account-numbers*))
account-type))
What I don't understand:
in the expression (setf (customer-name my-account) "Sally Sue") does (customer-name my-account) return a SETFable slot-value customer-name of the the class bank-account which then SETF uses to set the value to "Sally Sue"?
is (setf (customer-name my-account) "Sally Sue") actually calling the function above?
as defined above is setf customer-name a function?
in the function above is customer-name in (setf customer-name) and 'customer-name in the body referring to the same thing?
the section states
second element is a symbol, typically the name of a function used to access the place the SETF function will set
if that's the case then why use the slot-value function inside the function's definition when the function can be used to access the place?
In many cases accessing and setting data, one needs two things:
a way to retrieve something from a data-structure
a way to set something in a data-structure
Thus one would define a setter function and a getter function. For simple cases they also may look simple. But for complex cases they may not. Now if you know the name of the getter, what is the name of the setter? Or: if you know the name of the setter, what is the name of the getter?
Common Lisp has the idea that you only need to know the name of the getter.
the getter is called, say, GET-FOO
then the setter function is called (SETF GET-FOO). Always.
the setter function can be invoked this way: (setf (get-foo some-bar) new-foo). Always.
So you write the GET-FOO function. You also write the (SETF GET-FOO) function and Common Lisp registers it as a setter function.
(SETF GET-FOO) is a list. It's also the name of a function. Here we have the exception: Common Lisp sometimes allows a list as a function name. Thus not all function names are symbols, some are actually lists.
(setf (customer-name my-account) "Sally Sue") is actually a call the the defined setter. my-account is a variable whose value will be bound to the account variable of the setter. "Sally Sue" is a string and it will be bound to the name variable of the setter.
As a developer you only have to know the getter:
use of the getter: (customer-name my-account)
use of the setter: (setf (customer-name my-account) "Sally Sue"). SETF is a macro, which expands into a call of the setter function.
(defun (setf customer-name) (name account)
(setf (slot-value account 'customer-name) name))
Above defines a setter function called (setf customer-name).
CL-USER 80 > (function (setf customer-name))
#<interpreted function (SETF CUSTOMER-NAME) 40A00213FC>
When the function gets called via the SETF macro, it calls another setter - this time using the access to a slot value via the slot name.
setf is a very complex macro that knows how to decode its first argument, which usually looks like a function call, as a "place" and then invokes whatever forms are necessary to set the place to the new value. It's not useful to think of (customer-name my-account) as returning anything in the setf expression. The setf macro applies rules defined in the HyperSpec to its place form and, as a default case, will transform
(setf (foo arg0 arg1 ...) new-val)
to
(funcall #'(setf foo) new-val arg0 arg1 ...)
The passage in Practical Common Lisp is explaining, in a somewhat elliptic way, what happens behind the scenes when you specify an :accessor option in a defclass slot definition.
Related
*Note: Despite having frequented StackOverflow for a long time, this is the first question that I have posted myself. Apologies if it's a bit verbose. Constructive criticism appreciated.
When I define a struct in Common Lisp using defstruct, a predicate function is automatically generated that tests whether its argument is of the type defined by the defstruct. Eg:
(defstruct book
title
author)
(let ((huck-finn (make-book :title "The Adventures of Huckleberry Finn" :author "Mark Twain")))
(book-p huck-finn))
=> True
However, when defining a class using defclass, such functions are seemingly not generated by default (is there a way to specify this?), so I'm trying to add this functionality myself, because I'd like a) for this syntax to be consistent between structs and classes, b) to have an abbreviation of (typep obj 'classname), which I need to write very often and is visually noisy,
and c) as a programming exercise, since I'm still relatively new to Lisp.
I could write a macro that defines a predicate function given the name of a class:
(defclass book ()
((title :initarg :title
:accessor title)
(author :initarg :author
:accessor author)))
;This...
(defmacro gen-predicate (classname)
...)
;...should expand to this...
(defun book-p (obj)
(typep obj 'book))
;...when called like this:
(gen-predicate 'book)
The name that I need to pass to defun must be of the form 'classname-p. Here's where I have difficulty. To create such a symbol, I could use the "symb" function from Paul Graham's On Lisp (p. 58). When it is run on the REPL:
(symb 'book '-p)
=> BOOK-P
My gen-predicate macro looks like this so far:
(defmacro gen-predicate (classname)
`(defun ,(symb classname '-p) (obj)
(typep obj ,classname)))
(macroexpand `(gen-predicate 'book))
=>
(PROGN
(EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN '|'BOOK-P| 'NIL T))
(SB-IMPL::%DEFUN '|'BOOK-P|
(SB-INT:NAMED-LAMBDA |'BOOK-P|
(OBJ)
(BLOCK |'BOOK-P| (TYPEP OBJ 'BOOK)))
NIL 'NIL (SB-C:SOURCE-LOCATION)))
T
It would seem that the symbol created by (symb 'book '-p) is actually considered |'BOOK-P| by the implementation (SBCL), not BOOK-P. Sure enough, this now works:
(let ((huck-finn (make-instance 'book)))
(|'BOOK-P| huck-finn))
=> True
Why is the symbol created by symb interned as |'BOOK-P|? In On Lisp (same page as above) Graham says: "Any string can be the print-name of a symbol, even a string containing lowercase letters or macro characters like parentheses. When a symbol's name contains such oddities, it is printed within vertical bars." No such oddities exist in this case, do they? And am I correct in thinking that the "print-name" of a symbol is what is actually displayed on the standard output when the symbol is printed, and is, in the case of such oddities, distinct from the form of the symbol itself?
To be able to write function-defining macros like gen-predicate - whose defined functions are named based on the arguments passed to the macro - seems to me like something that Lisp hackers have probably been doing for ages. User Kaz says here (Merging symbols in common lisp) that the "mashing-up" of symbols can often be avoided, but that would defeat the purpose of this macro.
Finally, assuming I could get gen-predicate to work how I want, what would be the best way of ensuring that it be called for each new class as they are defined? Much in the same way as initialize-instance can be customized to perform certain actions upon instantiation of a class, is there a generic function called by defclass that can perform actions upon definition of a class?
Thank you.
That's a usual problem: what gets passed to a Macro?
Compare calls like this:
(symb 'book '-p)
and
(symb ''book '-p)
Your macro form is this:
(gen-predicate 'book)
GEN-PREDICATE is a macro. classname is a parameter for this macro.
Now what is the value of classname inside the macro during code expansion? Is it book or 'book?
Actually it is the latter, because you wrote (gen-predicate 'book). Remember: macros see source code and the argument source gets passed to the macro function - not the value. The argument is 'book. Thus this gets passed. (QUOTE BOOK) is the same, only printed differently. So it is a two element list. The first element is the symbol QUOTE and the second element is the symbol BOOK.
Thus the macro now calls the function SYMB with the argument value (QUOTE BOOK) or, shorter, 'BOOK.
If you want to generate the predicate without the quote character, you need to write:
(gen-predicate book)
Alternatively you can also change the macro:
(symb classname '-p)
would be:
(symbol (if (and (consp classname)
(eq (first classname) 'quote))
(second classname)
classname))
Compare
We write
(defun foo () 'bar)
and not
(defun 'foo () 'bar) ; note the quoted FOO
DEFUN is a macro and the first argument is the function name. It's a similar problem then...
Second part of the question
I don't really know any good answer to that. I can't remember any easy way to run code (for example to define a function) after a class definition.
Maybe use the MOP, but that's ugly.
write a custom macro DEFINE-CLASS which does what you want: expands into DEFCLASS and the DEFUN.
iterate over all symbols in a package, find the classes and define the corresponding predicates
To address the second part of the question, classes are themselves objects, thanks to the MOP, so it might be possible to write an :after method on initialize-instance specialized on STANDARD-CLASS. But you should check the MOP to see whether defining such a method is allowed or not.
If it's possible, then yes, you can run code in response to the creation of a class; however, since you don't know the name of the class being created until runtime, you cannot spell it textually in the source, so you cannot use your macro (unless you use eval). You'd rather use something like
(let ((classname (class-name class)))
(compile (generate-my-predicate-symbol classname)
(lambda (x) (typep x classname))))
I think Rainer's suggestion to write your own DEFINE-CLASS macro is the way to go, I mean, the way a seasoned Lisper most likely would do it, if there aren't any other considerations at play. But I'm not really a seasoned Lisper, so I might be wrong ;)
I now have learnt about arrays and aref in Lisp. So far, it's quite easy to grasp, and it works like a charme:
(defparameter *foo* (make-array 5))
(aref *foo* 0) ; => nil
(setf (aref *foo* 0) 23)
(aref *foo* 0) ; => 23
What puzzles me is the aref "magic" that happens when you combine aref and setf. It seems as if aref knew about its calling context, and would then decide whether to return a value or a place that can be used by setf.
Anyway, for the moment I just take this as granted, and don't think about the way this works internally too much.
But now I wanted to create a function that sets an element of the *foo* array to a predefined value, but I don't want to hardcode the *foo* array, instead I want to hand over a place:
(defun set-23 (place)
…)
So basically this function sets place to 23, whatever place is. My initial naive approach was
(defun set-23 (place)
(setf place 23))
and call it using:
(set-23 (aref *foo* 0))
This does not result in an error, but it also doesn't change *foo* at all. My guess would be that the call to aref resolves to nil (as the array is currently empty), so this would mean that
(setf nil 23)
is run, but when I try this manually in the REPL, I get an error telling me that:
NIL is a constant, may not be used as a variable
(And this absolutely makes sense!)
So, finally I have two questions:
What happens in my sample, and what does this not cause an error, and why doesn't it do anything?
How could I solve this to make my set-23 function work?
I also had the idea to use a thunk for this to defer execution of aref, just like:
(defun set-23 (fn)
(setf (funcall fn) 23))
But this already runs into an error when I try to define this function, as Lisp now tells me:
(SETF FUNCALL) is only defined for functions of the form #'symbol.
Again, I wonder why this is. Why does using setf in combination with funcall apparently work for named functions, but not for lambdas, e.g.?
PS: In "Land of Lisp" (which I'm currently reading to learn about Lisp) it says:
In fact, the first argument in setf is a special sublanguage of Common Lisp, called a generalized reference. Not every Lisp command is allowed in a generalized reference, but you can still put in some pretty complicated stuff: […]
Well, I guess that this is the reason (or at least one of the reasons) here, why all this does not work as I'd expect it, but nevertheless I'm curious to learn more :-)
A place is nothing physical, it's just a concept for anything where we can get/set a value. So a place in general can't be returned or passed. Lisp developers wanted a way to easily guess a setter from just knowing what the getter is. So we write the getter, with a surrounding setf form and Lisp figures out how to set something:
(slot-value vehicle 'speed) ; gets the speed
(setf (slot-value vehicle 'speed) 100) ; sets the speed
Without SETF we would need a setter function with its name:
(set-slot-value vehicle 'speed 100) ; sets the speed
For setting an array we would need another function name:
(set-aref 3d-board 100 100 100 'foo) ; sets the board at 100/100/100
Note that the above setter functions might exist internally. But you don't need to know them with setf.
Result: we end up with a multitude of different setter function names.
The SETF mechanism replaces ALL of them with one common syntax. You know the getter call? Then you know the setter, too. It's just setf around the getter call plus the new value.
Another example
world-time ; may return the world time
(setf world-time (get-current-time)) ; sets the world time
And so on...
Note also that only macros deal with setting places: setf, push, pushnew, remf, ... Only with those you can set a place.
(defun set-23 (place)
(setf place 23))
Above can be written, but place is just a variable name. You can't pass a place. Let's rename it, which does not change a thing, but reduces confusion:
(defun set-23 (foo)
(setf foo 23))
Here foo is a local variable. A local variable is a place. Something we can set. So we can use setf to set the local value of the variable. We don't set something that gets passed in, we set the variable itself.
(defmethod set-24 ((vehicle audi-vehicle))
(setf (vehicle-speed vehicle) 100))
In above method, vehicle is a variable and it is bound to an object of class audi-vehicle. To set the speed of it, we use setf to call the writer method.
Where does Lisp know the writer from? For example a class declaration generates one:
(defclass audi-vehicle ()
((speed :accessor vehicle-speed)))
The :accessor vehicle-speed declaration causes both reading and setting functions to be generated.
The setf macro looks at macro expansion time for the registered setter. That's all. All setf operations look similar, but Lisp underneath knows how to set things.
Here are some examples for SETF uses, expanded:
Setting an array item at an index:
CL-USER 86 > (pprint (macroexpand-1 '(setf (aref a1 10) 'foo)))
(LET* ((#:G10336875 A1) (#:G10336876 10) (#:|Store-Var-10336874| 'FOO))
(SETF::\"COMMON-LISP\"\ \"AREF\" #:|Store-Var-10336874|
#:G10336875
#:G10336876))
Setting a variable:
CL-USER 87 > (pprint (macroexpand-1 '(setf a 'foo)))
(LET* ((#:|Store-Var-10336877| 'FOO))
(SETQ A #:|Store-Var-10336877|))
Setting a CLOS slot:
CL-USER 88 > (pprint (macroexpand-1 '(setf (slot-value o1 'bar) 'foo)))
(CLOS::SET-SLOT-VALUE O1 'BAR 'FOO)
Setting the first element of a list:
CL-USER 89 > (pprint (macroexpand-1 '(setf (car some-list) 'foo)))
(SYSTEM::%RPLACA SOME-LIST 'FOO)
As you can see it uses a lot of internal code in the expansion. The user just writes a SETF form and Lisp figures out what code would actually do the thing.
Since you can write your own setter, only your imagination limits the things you might want to put under this common syntax:
setting a value on another machine via some network protocol
setting some value in a custom data structure you've just invented
setting a value in a database
In your example:
(defun set-23 (place)
(setf place 23))
you can't do it just like that, because you have to use setf in context.
This will work:
(defmacro set-23 (place)
`(setf ,place 23))
CL-USER> (set-23 (aref *foo* 0))
23
CL-USER> *foo*
#(23 NIL NIL NIL NIL)
The trick is, setf 'knows' how to look at real place its arguments come from, only for limited number of functions. These functions are called setfable.
setf is a macro, and to use it the way you wanted to, you also have to use macros.
The reason why you have not been getting errors, is that you actually successfully modified lexical variable place which was bound to copy of selected array element.
I would like to do something akin to this:
(defstruct person
real-name
(fake-name real-name)) ;if fake-name not supplied, default to real-name
However, Common Lisp says The variable REAL-NAME is unbound. So how can I get the constructor to evaluate its arguments sequentially (like I can with function keyword arguments), or how else should I be better doing this?
One way is:
(defstruct (person
(:constructor make-person (&key real-name
(fake-name real-name))))
real-name
fake-name)
You can essentially tailor the constructor function to your needs, including
providing a different name than make-xxx
having Lisp generate a "by-order-of-arguments" (BOA) constructor instead of a keyword-based one
Consider
(defstruct (person
(:constructor make-person (real-name
&optional (fake-name real-name))))
real-name
fake-name)
You can even initialize constructed fields using the &aux lambda-list keyword:
(defstruct (person
(:constructor make-person (real-name
&aux (fake-name (format nil
"fake-of-~A"
real-name)))))
real-name
fake-name)
numberp is a predicate in Lisp, and (numberp 1) returns T as expected. But if I only type numberp in the console, it prompts that the variable name is undefined.
What's the difference between these 2?
The question is slightly wrong already.
We are talking about different things in Common Lisp:
symbol : that's a data structure in Lisp. A symbol is a data object with a name, a value, a function, a package and possibly more.
In Common Lisp the symbol can have both a value and a function (or macro).
a variable is an identifier for a value in Lisp code
There are top-level variables defined by DEFVAR and DEFPARAMETER. There are also local variables defined by LAMBDA, DEFUN, LET, LET* and others.
(defun foo (i-am-a-variable) ...)
(defparameter *i-am-a-global-variable* ...)
a named function is an identifier for a function in Lisp code. Named functions are introduced on the top-level by DEFUN, DEFGENERIC and DEFMETHOD. There are also local named functions defined by FLET and LABELS.
Example:
(defun i-am-a-function (foo) ...)
(flet ((i-am-a-function (foo) ...)) ...)
To further complication function names and variable names are symbols in the source code.
Example:
(type-of (second '(defun foo () nil))) --> SYMBOL
Let's look at functions and variables:
(defun foo ()
(let ((some-name 100))
(flet ((some-name (bar) (+ bar 200)))
(+ some-name (some-name some-name)))))
Above code uses a variable and a function with the same symbol in the source code. Since functions and variables have their own namespace, there is no collision.
(+ some-name (some-name some-name))
Above then means we add the variable to the result of the function call on the variable.
This has the practical effect that you can do something like this:
(defun parent (person) ...)
(defun do-something (parent)
(parent parent))
You don't have to fear that your local variable names will shadow a global (or local) function. They simply are in different namespaces.
In Scheme there is only one namespace and we have to write
(define (foo lst) (list 'a lst 'n))
where in Common Lisp we can write:
(defun foo (list) (list 'a list 'n))
In Common Lisp there is no need to write lst instead of list - because there is no clash between the local variable list and the global function list.
Accessing the other namespace
To get a function object stored in a variable you can use FUNCTION.
(let ((my-function (function numberp)))
(funcall my-function 10))
(function foo) can be written shorter as #'foo.
FUNCALL calls a function object.
OTOH, if you want to store a function object from a variable in the function namespace, there is only one way:
(setf (symbol-function 'foo) my-function)
It is also necessary that the object is really a function and not something else (a number, a string, ...). Otherwise you'll see an error.
The side effect of this is that a Common Lisp never has to check if in (foo bar) the FOO is really a function. There is no possibility that it can be other than a function or undefined.
Functions and variables live in different namespaces in Common Lisp.
So when you use a name in a position where a function is expected (i.e. at the head of a list that is being evaluated), it looks for a function (or macro) with that name. If you use the same name at a position where a variable is expected, it looks for a variable with that name.
In your case there is a function named numberp, but not variable named numberp, so the second case causes an error.
One of the differences between Scheme (one Lisp dialect, so to speak) and Common Lisp is that in Scheme, there is one namespace for variables and functions, whereas in CL, there are two separate namespaces.
Thus, in Scheme, "define" sets this one-and-only name-to-value assoc, whereas in CL, there is "define" for the value and "defun" for the function association.
So, in CL you can:
(define foo ...something...)
(defun foo ...somethingElse...)
to confuse the reader.
In Scheme, there is only one:
(define foo something)
If this is good or bad has been an almost religious dispute in the past...
Consider this piece of code:
(defvar lst '(1 1))
(defmacro get-x (x lst)
`(nth ,x ,lst))
(defun get-y (y lst)
(nth y lst))
Now let us assume that I want to change the value of the elements of the list called lst, the car with get-x and the cdr with get-y.
As I try to change the value with get-x (with setf) everything goes fine but if I try it with get-y it signals an error (shortened):
; caught STYLE-WARNING:
; undefined function: (SETF GET-STUFF)
Why does this happen?
I myself suspect that this happens because the macro simply expands and the function nth simply returns a reference to the value of an element in the list and the function on the other hand evaluates the function-call to nth and returns the value of the referenced value (sounds confusing).
Am I correct in my suspicions?
If I am correct then how will one know what is simply a reference to a value and an actual value?
The error does not happen with the macro version, because, as you assumed, the expression (setf (get-x some-x some-list) some-value) will be expanded (at compile-time) into something like (setf (nth some-x some-list) some-value) (not really, but the details of setf-expansion are complex), and the compiler knows, how to deal with that (i.e., there is a suitable setf expander defined for function nth).
However, in the case of get-y, the compiler has no setf expander, unless you provide one. The easiest way to do so would be
(defun (setf get-y) (new-value x ls) ; Note the function's name: setf get-y
(setf (nth x ls) new-value))
Note, that there are a few conventions regarding setf-expanders:
The new value is always provided as the first argument to the setf function
All setf functions are supposed to return the new value as their result (as this is, what the entire setf form is supposed to return)
There is, BTW, no such concept as a "reference" in Common Lisp (at least not in the C++ sense), though there once were Lisp dialects which had locatives. Generalized place forms (ie., setf and its machinery) work very differently from plain C++ style references. See the CLHS, if you are curious about the details.
SETF is a macro.
The idea is that to set and read elements from data structures are two operations, but usually require two different names (or maybe even something more complex). SETF now enables you to use just one name for both:
(get-something x)
Above reads a datastructure. The inverse then simply is:
(setf (get-something x) :foobar)
Above sets the datastructure at X with :FOOBAR.
SETF does not treat (get-something x) as a reference or something like that. It just has a database of inverse operations for each operation. If you use GET-SOMETHING, it knows what the inverse operation is.
How does SETF know it? Simple: you have to tell it.
For The NTH operation, SETF knows how to set the nth element. That's builtin into Common Lisp.
For your own GET-Y operation SETF does not have that information. You have to tell it. See the Common Lisp HyperSpec for examples. One example is to use DEFUN and (SETF GET-Y) as a function name.
Also note following style problems with your example:
lst is not a good name for a DEFVAR variable. Use *list* as a name to make clear that it is a special variable declared by DEFVAR (or similar).
'(1 2) is a literal constant. If you write a Common Lisp program, the effects of changing it are undefined. If you want to change a list later, you should cons it with LIST or something like COPY-LIST.