This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Problem with "initialize-instance"

6 posts · 4493 views

I try to experiment with classes in LISP and I stuck at the following problem already at a very beginning level.
I define two classes "BIg" and "Small" so that "Small" is a subclass of "Big":
(defclass Big () 
  ( (my-value  :accessor my-value)
   ))

(defclass Small (Big)  () )
For the class "Small" I define an after-method of initialization:
(defmethod initialize-instance :after ( (item Small) &key )
  (setf (my-value item) 13)
  )
At this stage there is no problem with creating instances of both classes.
But then I execute the following code:
(defgeneric Func (item) )

(defmethod initialize-instance :after ( (item Big) &key )
  (setf (my-value item) (Func 666) )
  )
Clearly, there are no methods defined for a new generic function Func and an attempt to create an instance of the class "Big" leads to errors.
But by some reason attempts to create instances of the class "Small", e.g. calls
(setf x (make-instance 'Small ) )
also give the same error message saying that (Func 666) cannot be computed!
My question is: why "initialize-instance" chooses method for the class "Big" even when an instance of the class "Small" is created?
To understand LISP, you must first understand LISP.

Re: Problem with "initialize-instance"

abvgdeika wrote:But by some reason attempts to create instances of the class "Small", e.g. calls
(setf x (make-instance 'Small ) )
also give the same error message saying that (Func 666) cannot be computed!
My question is: why "initialize-instance" chooses method for the class "Big" even when an instance of the class "Small" is created?
A "Small" is a "Big" (Small is a subclass of Big)!

Re: Problem with "initialize-instance"

Situation is not so easy. The code
(defmethod initialize-instance :after ( (item Big) &key )
  (setf (my-value item) 666 )
  )

(setf x (make-instance 'Small ) )
results in creating an instance "x" having my-value 13, as expected since the method of initialization for the class "Small" is applied.
But replacing 666 by (Func 666) in the method definition for the class "Big" resuts in error even when creating instances of "Small".
Can someone explain this?
To understand LISP, you must first understand LISP.

Re: Problem with "initialize-instance"

abvgdeika wrote:Situation is not so easy. The code
(defmethod initialize-instance :after ( (item Big) &key )
  (setf (my-value item) 666 )
  )

(setf x (make-instance 'Small ) )
results in creating an instance "x" having my-value 13, as expected since the method of initialization for the class "Small" is applied.
But replacing 666 by (Func 666) in the method definition for the class "Big" resuts in error even when creating instances of "Small".
Can someone explain this?
I just did -- a Small is a Big. The initalize-instance function consists of _all_ the relevant :before methods, the "main" method, and _all_ the relevant :after methods -- the method you defined for a Big is also relevant to a Small, since a Small is a Big, therefore the :after method runs and you get your error. The order is most-relevant to least-relevant on the way in (:before methods), and least-relevant to most-relevant on the way out (:after methods), so the :after method for Big runs before the :after method for Small -- it sets the slot to 666 and then sets it to 13 -- which is why you see 13 in the resulting object if you fix the error in the Big method.

Make the initialize-instance methods print something, so you can see what's happening.

Re: Problem with "initialize-instance"

Thank you for the explanation! I would say this is not so economic behaviour of LISP processor,
to run first all available methods and then to choose appropriate result. It seems much more natural to choose first
appropriate method and then to run it.
To understand LISP, you must first understand LISP.

Re: Problem with "initialize-instance"

abvgdeika wrote:Thank you for the explanation! I would say this is not so economic behaviour of LISP processor,
to run first all available methods and then to choose appropriate result. It seems much more natural to choose first
appropriate method and then to run it.
It doesn't run them and then choose a result; it only runs what it needs to...before and after methods are meant to all run. It would be broken if it didn't run them all, since they all contribute to the meaning of the method. E.g., what would happen if you defined a (main; not before/after/etc.) method on Big but not on Small (so you intend for the Big method to run on smalls), and that method relies on some initialization done in a :before method (defined on Bigs, of course). If you wrote a :before method for Small that didn't duplicate that initialization, creating a Small would error out -- it has the run the :before method for Small, then the :before method for Big, then the main method, then the :after method for Big (if there is one), then the :after method for Small in order to ensure everything that needs to get done gets done. (There's also an :around method; if that exists, it gets called instead of the before/main/after sequence -- it's expected to use call-next-method to (eventually) invoke those).