Re: Can sub-classes initialize-instance modify base-classes slot *before* base's initialize-instance executes?
- From: Mirko.Vukovic@xxxxxxxxx
- Date: Thu, 9 Oct 2008 11:54:46 -0700 (PDT)
On Oct 9, 2:25 pm, Rainer Joswig <jos...@xxxxxxx> wrote:
In article
<704974e2-6713-4557-9a0c-8a5c5cb19...@xxxxxxxxxxxxxxxxxxxxxxxxxxx>,
Mirko.Vuko...@xxxxxxxxx wrote:
I suspect the answer is no, and in which case I will revisit my
concept. But here is the story.
I have a base class that initializes storage. One of its subclasses
needs extra padding around the storage. The base classes initializes
the padding to zero, and the subclasses ought to change that. Is
there some way to specify this within the standard CLOS machinery?
Here is the example code:
(in-package :cl-user)
(defclass base ()
((dim
:initform 12
:accessor dim)
(padding
:initform 0
:accessor padding
:initarg :padding
:documentation "Padding is necessary for some higher order
interpolations")
(storage
:initform nil
:accessor storage)))
(defmethod initialize-instance :after ((this base) &key)
(format t "Initializing base ~a~%" this)
(setf (storage this) (make-array (+ (dim this)
(padding this))
:initial-element 0d0)))
(defclass sub1a (base)
((dummy
:initform 2d0
:accessor dummy))
(:documentation "This will implement a higher order interpolations
that needs padding")
;; I would like to modify padding here.
(defmethod initialize-instance :after ((this sub1a) &key)
(format t "Initializing sub ~a~%" this)
(setf (padding this) 2))
Sure. Why not. Remember that all :after methods are running.
CL-USER 26 > (defclass c1 () (a))
#<STANDARD-CLASS C1 200AFF37>
CL-USER 27 > (defclass c2 (c1) ())
#<STANDARD-CLASS C2 200AE0B7>
CL-USER 28 > (defmethod initialize-instance :after ((object c1) &key) (setf (slot-value object 'a) 'c1-value))
#<STANDARD-METHOD INITIALIZE-INSTANCE (:AFTER) (C1) 200964C3>
CL-USER 29 > (defmethod initialize-instance :after ((object c2) &key) (setf (slot-value object 'a) 'c2-value))
#<STANDARD-METHOD INITIALIZE-INSTANCE (:AFTER) (C2) 21E2D45F>
CL-USER 30 > (describe (make-instance 'c2))
#<C2 21A36597> is a C2
A C2-VALUE
The slot is set twice. first to c1-value and then to c2-value.
First the :after method for C1 is running, then the :after method
for C2.
To get what I want, I need to do
(make-instance 'sub1a :padding 2)but I would prefer to do just
(make-instance 'sub1a)This, of course does not work, because first the base's initialize-
instance method is called, which sort-of makes sense.
But then the :after methods are running. The :after methods
from the subclass is running later.
Similar, all the :before methods are running. The :before
methods from the subclasses are running first:
For a method like initialize-instance with an object of class C2:
:after c2
:after c1
primary c2 -> call-next-method -> primary c1
:before c1
:after c2
The value of the primary method for c2 is returned as the value
for the generic function call.
(there are also :around methods)
The first approach looks kind of kludgy, even though Keene (yep, I
went to the library and got the CLOS book) suggests using constructors
to hide the ugly make-instance details.
In real world, the base class is a an "abstract/virtual" (not sure of
the difference) class for a differential equation solver, while the
(layered) subclasses are particular instances of the solvers, some of
which build on top of others. The base class provides the basic
storage, and methods for storing, accessing, and numerical
computations.
Also remember this:
CL-USER 33 > (defclass ce1 ()
((a :initform 'ce1-value)))
#<STANDARD-CLASS CE1 2009B607>
CL-USER 34 > (describe (make-instance 'ce1))
#<CE1 20099607> is a CE1
A CE1-VALUE
CL-USER 35 > (defclass ce2 ()
((a :initform 'ce2-value)))
#<STANDARD-CLASS CE2 200A60D7>
CL-USER 36 > (describe (make-instance 'ce2))
#<CE2 200DEB8F> is a CE2
A CE2-VALUE
Slots with the same name are merged. CE2 has only
one slot named A. The initform for CE2 will be used
when you make an instance of CE2.
Thanks,
Mirko
--http://lispm.dyndns.org/
Thanks Rainer. It works wonderfully.
Indeed, I did not think of :before.
For future reference, I am assuming your diagram had a typo. Here is
how I understand the execution order
:before c2
:before c1
primary c2 -> call-next-method -> primary c1
:after c1
:after c2
Mirko
.
- References:
- Prev by Date: Re: Can sub-classes initialize-instance modify base-classes slot *before* base's initialize-instance executes?
- Next by Date: Re: Can sub-classes initialize-instance modify base-classes slot *before* base's initialize-instance executes?
- Previous by thread: Re: Can sub-classes initialize-instance modify base-classes slot *before* base's initialize-instance executes?
- Next by thread: Re: Can sub-classes initialize-instance modify base-classes slot *before* base's initialize-instance executes?
- Index(es):
Relevant Pages
|