When is an initform used? - lisp

I'm forming a class for some work on molecular dynamics as follows:
(defclass %atom (particle)
((name :initarg :name :initform (error "Every atom in the system must have a name!"))
(mass :accessor mass :initarg :mass :initform (getmass name))
(charge :accessor charge :initarg :charge :initform (getcharge name))))
Initially I thought that I could somehow refer to other slots within the class definition with an initform i.e. (getmass name) - but that turns out to be untrue (or does it?!?). Instead, I'm told that initialize-instance would be the place to put all that initialization stuff... fair enough.
The question I have, then, is when is :initform used? What's the idiomatic preference? I've seen it used as above for generating (error "...") code, and also to initialize default arguments when an :initarg is not provided. But both of those could easily fit into initialize-instance and may make more sense there. Is there a particular way :initform is generally used?

Usually one would use :initform to give a slot some default value. With defclass one can't compute initforms simply based on other slots. There are also other complications, so :initform should be used for simple forms.
Examples
set the z slot of a 3d-vector object to 0.0
set the list of windows in a screen object to NIL
set the 'key function' slot in an object to #'identity
set the 'report string' slot in an error to "an error occured"
Any other more complicated set up of slot values should be done in a method. If the object needs to be set up automatically after MAKE-INSTANCE use an :AFTER method to INITIALIZE-INSTANCE.

To complicate things a little bit further, there is also the class option :default-initargs.
Personally I use :default-initargs and :initform as shortcuts when the full power of an after-method for initialize-instance is not needed, and :initform when the slot doesn't have an :initarg.

Related

Properly load-file for interactive Common Lisp development

I would like to know, what is the common approach to common-lisp interactive development in emacs (i use sly, but i think the slime instructions should be the same)
say i have this file:
(eval-when (:compile-toplevel :load-toplevel :execute)
(ql:quickload :closer-mop))
(in-package :cl-user)
(defpackage :shapes
(:use :closer-common-lisp-user)
(:export #:rectangle))
(in-package :shapes)
(defclass rectangle ()
((height :initform 0.0 :initarg :height)
(width :initform 0.0 :initarg :width)))
which is quite simple.
Evaluating it experssion by expression seems to be ok, while loading the whole file (C-c C-l) gives me the following error:
The variable SHAPES:RECTANGLE is unbound.
[Condition of type UNBOUND-VARIABLE]
stripping it down to
(in-package :cl-user)
(defpackage #:shapes
(:use #:cl-user)
(:export #:rectangle))
(in-package #:shapes)
(defclass rectangle ()
((height :initform 0.0 :initarg :height)
(width :initform 0.0 :initarg :width)))
doesn't make any change.
compile-and-load (C-c C-k) doesn't work either, leaving me with:
; in: DEFCLASS RECTANGLE
; (SHAPES::DEFCLASS SHAPES:RECTANGLE NIL
; ((SHAPES::HEIGHT :INITFORM 0.0 :INITARG :HEIGHT)
; (SHAPES::WIDTH :INITFORM 0.0 :INITARG :WIDTH)))
;
; caught COMMON-LISP:STYLE-WARNING:
; undefined function: SHAPES::DEFCLASS
i see that defclass can't be properly resolved to from cl-user:defclass, but can't see the way to fix it.
I wonder what am i missing?
And what is the common flow for developing interactively in emacs?
The underlying problem here is that you are confusing two ways that packages can be used in CL. A package generally serves one, or both, of two purposes:
it can export a number of symbols, providing some kind of interface to functionality;
it can be a package in which other packages are used or from which symbols are imported, but which does not export any symbols (unless it is also a type 1 package).
There is no formal distinction between these types of packages, but there very often is an informal distinction. Packages which are of the second type above are often called *-USER with the canonical example being the CL-USER package. They often (but not always) serve as places for scratch work.
So what you are doing is defining a package whose use list is such a user package. You can see that this is not going to work by simply looking at the external symbols of this package. From your second example:
> (do-external-symbols (s (find-package "CL-USER"))
(print s))
nil
In other words, CL-USER exports no symbols at all. This means that your SHAPES package will initially not have access to any symbols at all, and in particular none of the CL symbols will be present.
Well, the language defines a canonical 'type 1' package, which is CL: the whole purpose of this package is to export the symbols which define the Common Lisp language, and only those symbols. So the definition of the SHAPES packages in your second example should be
(defpackage #:shapes
(:use #:cl)
(:export #:rectangle))
(Note that SHAPES is a type 1 package: it is providing some functionality in the form of SHAPES:RECTANGLE, and presumably is therefore intended to be used by other packages.)
Closer to MOP provides two packages which mirror the standard CL and CL-USER packages:
CLOSER-COMMON-LISP is like CL except that various symbols are replaced by ones defined by Closer to MOP, and there may be additional MOP symbols;
CLOSER-COMMON-LISP-USER is like CL-USER: it's a package intended general use, which users CLOSER-COMMON-LISP but which does not export any symbol at all.

Is there a way to get the slots of a class?

I have a class like this one
(defclass shape ()
((color :initform :black)
(thickness :initform 1)
(filledp :initform nil)
(window :initform nil)))
Is there a function in common-lisp how to get a list of those slots if i only know instance of this class?
Many Common Lisp implementations support the CLOS Meta-object Protocol. This provides introspective operations for classes, slots and other meta objects.
In LispWorks the corresponding functions are directly accessible in the package CL-USER.
CL-USER 139 > (defclass shape ()
((color :initform :black)
(thickness :initform 1)
(filledp :initform nil)
(window :initform nil)))
#<STANDARD-CLASS SHAPE 40202910E3>
CL-USER 140 > (mapcar #'slot-definition-name
(class-direct-slots (class-of (make-instance 'shape))))
(COLOR THICKNESS FILLEDP WINDOW)
The functions slot-definition-name and class-direct-slots are defined by the Meta Object Protocol for CLOS and are supported in many Common Lisp implementations - just the package they are in may differ. In SBCL for example one might find them in the package SB-MOP.
From a class we can get the list of direct slots. Direct slots are the slots which are directly defined for that class and which are not inherited. If you want to get a list of all slots, then use the function class-slots.
Slot here means that we get a slot definition object, which describes the slot. To get the name of the slot, you have to retrieve the name from the slot definition object using the function slot-definition-name.

How does using the SETF function to extend SETF work?

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.

Trying to understand setf + aref "magic"

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.

Common Lisp Macros: correct expansion of a generated list

I am building a mechanism to take an arbitrary CLOS object and return a hash from it (useful in my debugging experience).
However, I am not sure how to force a variable expansion. I sense that the solution lies with a correct use of gensym, but I'm not sure how.
;;helper macro
(defun class-slots-symbols (class-name)
"Returns a list of the symbols used in the class slots"
(mapcar 'closer-mop:slot-definition-name
(closer-mop:class-slots
(find-class class-name))))
;;macro that I am having difficulty with
(defmacro obj-to-hash (obj-inst)
"Reads an object, reflects over its slots, and returns a hash table of them"
`(let ((new-hash (make-hash-table))
(slot-list (class-slots-symbols (type-of ,obj-inst))))
;;The slot-list needs to expand out correctly in the with-slots form
(with-slots (slot-list) obj-inst
(loop for slot in slot-list do ;and also here
(format t "~a~&" slot)
(hashset new-hash (string slot) slot)))))
After a macroexpand-1, I find that that this expands into the following code (*bar* is a class object):
(macroexpand-1 '(obj-to-hash *bar*))
LET ((NEW-HASH (MAKE-HASH-TABLE))
(SLOT-LIST (CLASS-SLOTS-SYMBOLS (TYPE-OF *BAR*))))
(WITH-SLOTS (SLOT-LIST) ;; <-- this needs to be expanded to *bar*'s slots
*BAR*
(LOOP FOR SLOT IN SLOT-LIST ;;<-- not so important
DO (FORMAT T "~a~&" SLOT) (HASHSET NEW-HASH (STRING SLOT) SLOT))))
Obviously, the problem is that slot-list is not being expanded. Less obvious (to me) is the solution.
Followup: After Rainer pointed me in the right direction:
(defun class-slots-symbols (class-instance)
"Returns a list of the symbols used in the class slots"
(mapcar 'closer-mop:slot-definition-name
(closer-mop:class-slots
(class-of class-instance))))
(defun object-to-hash (obj)
"Reflects over the slots of `obj`, and returns a hash table mapping
slots to their values"
(let ((new-hash (make-hash-table))
(slot-list (class-slots-symbols obj)))
(loop for slot in slot-list do
(hashset new-hash (string slot)
(slot-value obj slot)))
new-hash))
Just looking at it I can see no reason why this should be a macro. Rewriting it as a function will save you a lot of trouble.
The use of WITH-SLOTS is not possible they way you try it. The object is not known in general until runtime. The compiler needs to know the slots of the object at compile time already. You need to use SLOT-VALUE and look up the slot value at runtime.
You are thinking in many ways too complicated and your code is slightly confused. You can get rid of some confusion by following simple rules and avoiding some wording.
Let's look at your code:
First, it is not a helper macro, since what follows is a function.
;;helper macro
(defun class-slots-symbols (class-name)
Why take a class name? Why not use the class itself? Classes are first class objects. Write function with obvious interfaces. Elementary functions should work on the basic data types.
"Returns a list of the symbols used in the class slots"
In the class slots no symbols are used. slots have names, one can get this symbol.
(mapcar 'closer-mop:slot-definition-name
(closer-mop:class-slots
(find-class class-name))))
It is no wonder you have a problem with this macro. It is simply because it should be a function, not a macro. Macros are for source transformation. All you need is a simple computation, so no macro is needed
;;macro that I am having difficulty with
(defmacro obj-to-hash (obj-inst)
Poor wording: obj-inst. Either name it object or instance. Not both.
"Reads an object, reflects over its slots, and returns a hash table of them"
Poor documentation: you don't READ anything. Read is an I/O operation and in your code is none. You are talking about an 'object', but above you have something like 'obj-inst'. Why talk about the same thing in two different ways? You may want to document what the hash table actual maps. From which keys to which values?
`(let ((new-hash (make-hash-table))
new-hash is also a poor name. Basically the thing is a hash-table.
(slot-list (class-slots-symbols (type-of ,obj-inst))))
Why TYPE-OF and then later in the helper function call FIND-CLASS? Common Lisp has CLASS-OF, which returns the class directly.
;;The slot-list needs to expand out correctly in the with-slots form
(with-slots (slot-list) obj-inst
Above won't work since WITH-SLOTS expects slot names at compile time, not a slot-list.
(loop for slot in slot-list do ;and also here
(format t "~a~&" slot)
(hashset new-hash (string slot) slot)
HASHSET is not needed, unless it does something special. The usual way to set values is via SETF. SETF takes the form to read a place and the form to compute a value. That's all. It works for all kinds of data structures. One never needs to remember again how the writer function looks like (name, parameter list, ...).
))))
Here is my version:
Note that I use the package CLOS, you may want to use your package CLOSER-MOP
(defun class-slots-symbols (class)
"Returns a list of the symbol names of the class slots"
(mapcar 'clos:slot-definition-name
(clos:class-slots class)))
Above is a simple function taking a class and returning the list of slot names.
Next, we have a simple function, which in this form has been written a million times in Common Lisp:
(defun object-to-hash (object)
"returns a hashtable with the object's slots as keys and slot-values as values"
(let ((hash-table (make-hash-table)))
(loop for slot-name in (class-slots-symbols (class-of object))
do (setf (gethash slot-name hash-table)
(string (slot-value object slot-name))))
hash-table))
We can also rewrite it to slightly older style Lisp:
(defun object-to-hash (object &aux (hash-table (make-hash-table)))
"returns a hashtable with the object's slots as keys
and string versions of the slot-values as values"
(dolist (slot-name (class-slots-symbols (class-of object)) hash-table)
(setf (gethash slot-name hash-table)
(string (slot-value object slot-name)))))
Above is much simpler and has the whole confusion about macros, generating code, compile time information vs. runtime, ... removed. It is much easier to understand, maintain and debug.