Suppose I have a class called board:
(defclass board ()
((blocker :accessor blocker :initarg :blocker :initform 0))
According to this book I can define a custom setf for blocker by:
(defmethod (setf blocker) (new-blocker (b board))
(setf (slot-value b 'blocker) new-blocker))
However, steel bank common lisp will say function not defined, even though I have evaluated it. Does anyone know what's wrong here?
That looks correct. Note that you are redefining the already existing setf method that you created by specifying :accessor blocker. SBCL will give you a style-warning about that.
Your mistake is somewhere else. Are you in a different package, perhaps? Try to show the steps you have taken in your IDE to compile and load those forms, and to attempt to run that method invocation.
You have to declare a generic function before defining any methods.
(defgeneric (setf blocker) (new-blocker board))
See this chapter in Practical Common Lisp for an example.
Related
I am reading the Wikipedia article about CLOS.
It says that:
This dispatch mechanism works at runtime. Adding or removing methods thus may lead to changed effective methods (even when the generic function is called with the same arguments) at runtime. Changing the method combination also may lead to different effective methods.
Then, I inserted:
; declare the common argument structure prototype
(defgeneric f (x y))
; define an implementation for (f integer t), where t matches all types
(defmethod f ((x integer) y) 1)
Using SBCL and SLIME, I compiled the regions with code and had the following result:
CL-USER> (f 1 2)
1
Then, I added to the definition:
; define an implementation for (f integer real)
(defmethod f ((x integer) (y real)) 2)
Again, I repeated the process compiling the new region and using the REPL to eval:
CL-USER> (f 1 2.0)
2
First question, if CLOS had the opposite behavior of run-time dispatch (compile-time dispatch, I suppose), what would the result be?
Second question, I decided to comment out the second method, leaving just the generic function and the first written method. Then, I re-compiled the region with Emacs.
When calling the fuction fin the REPL with (f 1 2) I thought I would get 1 since the second method is out. Instead, I got 2.
CL-USER> (f 1 2.0)
2
Why did this happen?
The only way I can get back to (f 1 2) returning 1 is re-starting the Slime REPL and compiling the region (with the second method being commented out). Third question, is there a better way to have this result without having to re-start the REPL?
Thanks!
These two are actually the same question. The answer is: you are modifying a system while it is running.
If CLOS objects weren't re-definable at run-time, this would simply not work, or you'd not be allowed to do that. Try such re-definitions with basic structs (i. e. the things you get when using defstruct), and you will often run into pretty severe warnings or even errors when the change is not compatible. Of course, structs have other limitations, too, e. g. only single dispatch, so that it's not so easy to make an exactly analogous example. But try to remove a slot from a defstruct.
Just commenting out some source code doesn't change the fact that you evaluated (compiled and loaded) it before. You are manipulating a running system, and the source code is just that: source. If you want to remove a method from the running system, you can use remove-method (see also How to remove a defmethod for a struct). Most Lisp IDEs have ways to do that interactively, e. g. in SLIME using the SLIME inspector.
This asks about initializing slots from other slots. What I want to achieve instead is to take some arguments as input - perhaps but not necessarily to make-instance - and convert these arguments into the class slots for storage. In effect, I want to separate the implementation of the class from its (initialization) interface.
Is there a recommended way to achieve this?
The simplest way I can imagine is simply create a (defun make-my-object ...) as the interface. This may then call make-instance with appropriate arguments.
For example, imagine
(defclass my-object () (slot-1 slot-2))
(defun make-my-object (arg-1 arg-2)
(make-instance 'my-object
:slot-1 (+ arg-1 arg-2)
:slot-2 (- arg-1 arg-2)))
Other ways I can imagine include implementing an initialize-instance :after that takes arg-1 and arg-2 as keyword arguments and initializes slot-1 and slot-2 appropriately. However, since after methods are called in the least-specific-first-order, that means that superclass slots will be initialized before current-class slot. On the other hand, what looks more common is that one will take arguments for constructing current-class, and on the basis of these arguments, one will initialize the super-class slots.
The alternative is initialize-instance :before - or also :around - but if multiple classes in the hierarchy have such "interface-implementation" differences, I don't see this working, unless I can pass arguments to call-next-method.
Are there other ways?
EDIT: Thanks to #ignis volens for bringing to my notice that (one of) my main concern(s) is about superclass slots being initialized from subclass slots. Is there a recommended way to do this?
I am not sure I understand your question. The answer is almost certainly after methods on initialize-instance I think. You say that this will cause slots defined in superclasses to be initialized first: yes, it will, and that almost certainly what you want to happen. Slots defined in superclasses don't generally depend for their values on subclass slots (its always possible to think of exceptions to everything) and so initialising in least-specific first order is almost always what you want.
The two common ways of initializing slots that I use are either to simply declare what their initargs are in the definition:
(defclass minibeast ()
((legs :initform 'uncountable
:initarg :legs
:initarg :leg-count
:accessor legs)
(tentacles :initform 'many
:initarg :tentacles
:initarg :number-of-tentacles
:accessor tentacles)))
And now (make-instance 'minibeast :legs 87) does what you expect. And this works (because, obviously it has to if the two slots were defined in different classes):
(defclass awful-monster ()
((legs :initform 'uncountable
:initarg :legs
:initarg :leg-count
:accessor legs)
(appendages :initform 'many
:initarg :legs
:initarg :appendages)))
Now (make-instance 'awful-monster :legs 93) will result in an awful monster with 93 legs and 93 appendages.
However that method perhaps doesn't qualify as separating interface from implementation. You may also want to perform some computation when initialising slots. In both these cases after methods on initialize-instance are generally the right approach:
(defclass horrible-monster ()
((legs :initform 983
:accessor legs)
(eyes :initform 63
:accessor eyes)
(appendages
:reader appendages)))
(defmethod initialize-instance :after
((m horrible-monster) &key eyes legs (stalky-eyes t))
(with-slots ((e eyes) (l legs) appendages) m
(when eyes (setf e eyes))
(when legs (setf l legs))
(setf appendages (if stalky-eyes (+ e l) l))))
And now horrible monsters will get the appropriate number of appendages (I am not sure why horrible monsters don't know whether their eyes are on stalks or not: perhaps they don't have mirrors).
There are any number of other combinations of course. You might well not want to have user code call make-instance explicitly but wrap things up in some function:
(defun make-awful-thing (&rest args &key (sort-of-horrible-thing 'horrible-monster)
&allow-other-keys)
(let ((the-remaining-args (copy-list args)))
;; No doubt alexandria or something has a way of doing this
(remf the-remaining-args ':sort-of-horrible0thing)
(apply #'make-instance sort-of-horrible-thing the-remaining-args)))
And now, of course you can have some bespoke initialzation protocol easily:
(defgeneric enliven-horrible-thing (horrible-thing &key)
(:method :around ((horrible-thing t) &key)
(call-next-method)
t))
(defun make-awful-thing (&rest args &key (sort-of-horrible-thing 'horrible-monster)
&allow-other-keys)
(let ((the-remaining-args (copy-list args)))
;; No doubt alexandria or something has a way of doing this
(remf the-remaining-args ':sort-of-horrible0thing)
(apply #'enliven-horrible-thing
(apply #'make-instance sort-of-horrible-thing
the-remaining-args)
the-remaining-args)))
(defmethod enliven-horrible-thing ((horrible-thing horrible-monster)
&key (ichor t) (smell 'unspeakable))
...)
I have recently encountered a confusing dichotomy regarding structures in Lisp.
When creating a structure with (defstruct), we specify the slots by keyword (:slotname). But when accessing it, we use local symbols ('slotname).
Why? This makes no sense to me.
Also, doesn't this pollute the keyword package every time you declare a structure?
If I try to access the slots by keyword, I get confusing errors like:
When attempting to read the slot's value (slot-value), the slot :BALANCE is
missing from the object #S(ACCOUNT :BALANCE 1000 :CUSTOMER-NAME "John Doe").
I don't understand this message. It seems to be telling me that something right under my nose doesn't exist.
I have tried declaring the structure using local symbols; and also with unbound keywords (#:balance) and these don't work.
DEFSTRUCT is designed in the language standard in this way:
slot-names are not exposed
there is no specified way to get a list of slot-names of a structure class
there is no specified way to access a slot via a slot-name
thus at runtime there might be no slot-names
access to slots is optimized with accessor functions: static structure layout, inlined accessor functions, ...
Also explicitly:
slot-names are not allowed to be duplicate under string=. Thus slots foo::a and bar::a in the same structure class are not allowed
the effects of redefining a structure is undefined
The goal of structures is to provide fast record-like objects without costly features like redefinition, multiple inheritance, etc.
Thus using SLOT-VALUE to access structure slots is an extension of implementations, not a part of the defined language. SLOT-VALUE was introduced when CLOS was added to Common Lisp. Several implementations provide a way to access a structure slot via SLOT-VALUE. This then also requires that the implementation has kept track of slot names of that structure.
SLOT-VALUE is simply a newer API function, coming from CLOS for CLOS. Structures are an older feature, which was defined already in the first version of Common Lisp defined by the book CLtL1.
You used make-instance to create a class instance and then you are showing a struct, I am confused.
structs automatically build their accessor functions. You create it with make-account. Then you'd use account-balance instead of slot-value.
I don't know what is the expected behavior to use make-instance with a struct. While it seemed to work on my SBCL, you are not using structs right.
(defstruct account
(balance))
(make-account :balance 100)
#S(ACCOUNT :BALANCE 100)
(account-balance *)
100
With classes, you are free to name your accessor functions as you want.
;;(pseudocode)
(defclass bank-account ()
((balance :initform nil ;; otherwise it's unbound
:initarg :balance ;; to use with make-instance :balance
:accessor balance ;; or account-balance, as you wish.
)))
(make-instance 'bank-account :balance 200)
#<BANK-ACCOUNT {1009302A33}>
(balance *)
200
https://lispcookbook.github.io/cl-cookbook/data-structures.html#structures
http://www.lispworks.com/documentation/HyperSpec/Body/m_defstr.htm
the slot :BALANCE is missing from the object #S(ACCOUNT :BALANCE 1000 :CUSTOMER-NAME "John Doe").
The slot name is actually balance and the representation uses the generated initargs. With the class object, the error message might be less confusing:
When attempting to read the slot's value (slot-value), the slot :BALANCE is missing from the object #<BANK-ACCOUNT {1009302A33}>.
First of all, see Rainer's excellent answer on structures. In summary:
Objects defined with defstruct have named accessor functions, not named slots. Further the field names of these objects which are mentioned in the defstruct form must be distinct as strings, and so keywords are completely appropriate for use in constructor functions. Any use of slot-value on such objects is implementation-dependent, and indeed whether or not named slots exist at all is entirely implementation-dependent.
You generally want keyword arguments for the constructors for the reasons you want keyword arguments elsewhere: you don't want to have to painfully provide 49 optional arguments so you can specify the 50th. So it's reasonable that the default thing defstruct does is that. But you can completely override this if you want to, using a BOA constructor, which defstruct allows you to do. You can even have no constructor at all! As an example here is a rather perverse structure constructor: it does use keyword arguments, but not the ones you might naively expect.
(defstruct (foo
(:constructor
make-foo (&key ((:y x) 1) ((:x y) 2))))
y
x)
So the real question revolves around classes defined with defclass, which usually do have named slots and where slot-value does work.
So in this case there are really two parts to the annswer.
Firstly, as before, keyword arguments are really useful for constructors because no-one wants to have to remember 932 optional argument defaults. But defclass provides complete control over the mapping between keyword arguments and the slots they initialise, or whether they initialise slots at all or instead are passed to some initialize-instance method. You can just do anything you want here.
Secondly, you really want slot names for objects of classes defined with defclass to be symbols which live in packages. You definitely do not want this to happen:
(in-package "MY-PACKAGE")
(use-package "SOMEONE-ELSES-PACKAGE")
(defclass my-class (someone-elses-class)
((internal-implementation-slot ...)))
only to discover that you have just modified the definition of the someone-elses-package::internal-implementation-slot slot in someone-elses-class. That would be bad. So slot names are symbols which live in packages and the normal namespace control around packages works for them too: my-package::internal-implementation-slot and someone-elses-package::internal-implementation-slot are not (usually) the same thing.
Additionally, the whole keyword-symbol-argument / non-keyword-symbol-variable thing is, well, let's just say well-established:
(defun foo (&key (x 1))
... x ...)
Finally note, of course, that keyword arguments don't actually have to be keywords: it's generally convenient that they are because you need quotes otherwise, but:
(defclass silly ()
((foo :initarg foo
:accessor silly-foo)
(bar :initarg bar
:accessor silly-bar)))
And now
> (silly-foo (make-instance 'silly 'bar 3 'foo 9))
9
I'm trying to figure out what is the purpose of define-generic in goops library (http://wiki.call-cc.org/eggref/4/coops), it's similar to CLOS if it can help someone (I don't know CLOS either).
I can define a class and a method this way:
(define-class <complex> () (x y))
(define-method (sum (a <complex>) (b <complex>))
(make <complex>
'x (+ (slot-value a 'x) (slot-value b 'x))
'y (+ (slot-value a 'y) (slot-value b 'y))))
But what is the purpose of this?
(define-generic (sum <complex> <complex>))
From the docs:
[syntax] (define-generic (NAME ARGUMENT ...))
Defines a generic procedure, a procedure specialized for one or more
argument types. ARGUMENT ... defines the number of specialized
arguments this generic procedure shoud use to dispatch to the correct
method. The generic procedure may receive additional arguments, but
those will not be used to determine the method.
Could someone give me a simple example explaining the differences beetween define-method and define-generic?
A generic procedure is a special kind of object that consists of (one or) several specialised methods.
define-generic defines such an object, and define-method adds methods to it, creating it if it doesn't exist.
How can I attach an arbitrary tag to a closure in Scheme?
Here are a couple things I'd like to use this for:
(1) To mark closures that provide an interface to produce a string for what they represent, like what #kud0h asked for here. A general ->string procedure could include code something like this:
(display (if (stringable? x)
(x 'string)
x)
str-port)
(2) More generally, to determine if a closure is an "object" that obeys the rules of a general object interface, or maybe to tell the class of an object (something like what #KPatnode was asking about here).
I can't query a procedure to see if it supports a certain interface by calling it, because if it doesn't support a known interface, calling the procedure will produce unpredictable results, most likely a run-time error.
Chez Scheme has putprop and getprop procedures that allow you to add keys and values to symbols. However, closures can be anonymous, or bound to different symbols, so I'd prefer to attach a calling-convention tag to the closure itself, not a symbol that it's bound to.
The only idea I have right now is to maintain a global hash table of all "stringable" or "object" closures in the system. That seems a little clunky. Is there a simpler, more elegant, or more efficient way?
Racket has applicable structures: you can give a structure type an apply hook to be called if an instance is used as a function.
If you want a more portable solution, you can use a hash table to associate your data with certain procedures. Unless your Scheme provides weak hashtables, though, keep in mind that the hashtable will prevent the procedures from being garbage-collected.
I think you might, instead of tagging procedures per se, want to look at Racket's object system, which has a concept of interfaces. It sounds quite similar to what you're after.
You could go extreme and redefine lambda syntax. Something like this (but untested by me):
(define *properties* '()) ;; example only
(define-syntax lambda
(let-syntax ((sys-lambda
(syntax-rules ()
((_ args body ...)
(lambda args body ...)))))
(syntax-rules ()
((_ args body ...)
(let ((func (sys-lambda args body ...)))
(set! *properties*
(cons (cons func '(NO-PROPERTIES))
*properties*))
func)))))