I have a class that has methods specialized on it that are
expensive. I want to inherit from this class to include slots that can
hold precomputed values of these expensive methods. I want to make it
so that if I have an instance of the superclass, the expensive method
will be called, but if I have an instance of the subclass, the slot
value will be returned. I'm running into difficulties initializing the
slots. I need to invoke the expensive method, but since I have a
reference to the inheriting class, a call to to the function resolves
to a reader method. In Java, I'd say `super.c()' instead of
`c()'. What is the CLOS equivalent?
The line that I'm having trouble with is marked `tautology' below.
Ari.
(defclass dynamic ()
(slot-a :reader a)
(slot-b :reader b)
(defmethod c ((dy dynamic))
;expensive computations
)
(defmethod d ((dy dynamic))
;expensive computations
)
(defclass precomputed (dynamic)
(slot-c :reader c)
(slot-d :reader d))
(defmethod initialize-instance :after ((pc precomputed) &key c d)
(with-slots (slot-c slot-d) pc
(setf slot-c (c p)) ; tautology
(setf slot-d (d p))))
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
On Mon, 17 Jul 2006 19:01:49 -0700, Ari Krupnik <···@lib.aero> wrote:
>
>(defclass dynamic ()
> (slot-a :reader a)
> (slot-b :reader b)
>
>(defmethod c ((dy dynamic))
> ;expensive computations
> )
>
>(defmethod d ((dy dynamic))
> ;expensive computations
> )
>
>(defclass precomputed (dynamic)
> (slot-c :reader c)
> (slot-d :reader d))
>
>(defmethod initialize-instance :after ((pc precomputed) &key c d)
> (with-slots (slot-c slot-d) pc
> (setf slot-c (c p)) ; tautology
> (setf slot-d (d p))))
Ari, I would suggest getting rid of the readers for slot-c and
slot-d. In the c and d methods specialized on precomputed,
call-next-method if necessary to store the result in the
appropriate slot, then return the cached value.
--
Jack Unrue
Jack Unrue <·······@example.tld> writes:
> On Mon, 17 Jul 2006 19:01:49 -0700, Ari Krupnik <···@lib.aero> wrote:
>>
>>(defclass dynamic ()
>> (slot-a :reader a)
>> (slot-b :reader b)
>>
>>(defmethod c ((dy dynamic))
>> ;expensive computations
>> )
>>
>>(defmethod d ((dy dynamic))
>> ;expensive computations
>> )
>>
>>(defclass precomputed (dynamic)
>> (slot-c :reader c)
>> (slot-d :reader d))
>>
>>(defmethod initialize-instance :after ((pc precomputed) &key c d)
>> (with-slots (slot-c slot-d) pc
>> (setf slot-c (c p)) ; tautology
>> (setf slot-d (d p))))
>
> Ari, I would suggest getting rid of the readers for slot-c and
> slot-d. In the c and d methods specialized on precomputed,
> call-next-method if necessary to store the result in the
> appropriate slot, then return the cached value.
That's what I did to get around this difficulty. The problem I saw
with this solution was that I could initialize slot-c and slot-d in
initialize-instance and not have to check slot-boundp on every
access. It's not so much that I'm worried about spending time in the
lookup (though these methods are being called from the inner loop); I
thought that taking care of the initialization in initialize-instance
would make it clearer that c and d didn't actually perform any
computation, only returned the slot values.
Ari.
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
Ari Krupnik wrote:
> I have a class that has methods specialized on it that are
> expensive. I want to inherit from this class to include slots that can
> hold precomputed values of these expensive methods. I want to make it
> so that if I have an instance of the superclass, the expensive method
> will be called, but if I have an instance of the subclass, the slot
> value will be returned. I'm running into difficulties initializing the
> slots. I need to invoke the expensive method, but since I have a
> reference to the inheriting class, a call to to the function resolves
> to a reader method. In Java, I'd say `super.c()' instead of
> `c()'. What is the CLOS equivalent?
(call-next-method)
>
> The line that I'm having trouble with is marked `tautology' below.
>
> Ari.
>
>
> (defclass dynamic ()
> (slot-a :reader a)
> (slot-b :reader b)
>
> (defmethod c ((dy dynamic))
> ;expensive computations
> )
>
> (defmethod d ((dy dynamic))
> ;expensive computations
> )
>
> (defclass precomputed (dynamic)
> (slot-c :reader c)
> (slot-d :reader d))
Here is a possible way of doing it:
(defclass precomputed (dynamic)
(slot-c)
(slot-d))
(defmethod c ((p precomputed))
(unless (slot-boundp p 'slot-c)
(setf (slot-value p 'slot-c) (call-next-method)))
(slot-value p 'slot-c))
"Joe Marshall" <··········@gmail.com> writes:
> Ari Krupnik wrote:
>> to a reader method. In Java, I'd say `super.c()' instead of
>> `c()'. What is the CLOS equivalent?
>
> (call-next-method)
As far as I understand, call-next-method is only available inside
defmethod and so cannot help me here. The Javaism I mentioned is
available anywhere within a class definition.
> Here is a possible way of doing it:
>
> (defclass precomputed (dynamic)
> (slot-c)
> (slot-d))
>
> (defmethod c ((p precomputed))
> (unless (slot-boundp p 'slot-c)
> (setf (slot-value p 'slot-c) (call-next-method)))
> (slot-value p 'slot-c))
Is there a difference between your suggestion and Jack Unrue's that I
missed?
Ari.
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
Ari Krupnik wrote:
>
> Is there a difference between your suggestion and Jack Unrue's that I
> missed?
Ummm... Nope. I should have paid more attention.
Joe Foran <········@gmail.com> writes:
> Hi,
>
> I'm currently trying to teach myself Lisp and am working my way
> through Paul Graham's book. One of the exercises for chapter 4 asks
> the reader to define a function that takes a hash table and returns a
> corresponding assoc-list.
>
> My attempt at an answer is as follows
>
> (defun assoc-from-hash (ht)
> (let ((assocList nil))
> (maphash #'(lambda (k v)
> (append assocList (list (cons k v)))) ht )
> assocList))
>
> I created a hash table as follows
>
> (setf ht (make-hash-table))
> (setf (gethash 'animal ht) 'dog)
> (setf (gethash 'vegetable ht) 'carrot)
> (setf (gethash 'mineral ht) 'zinc)
>
> and when I call the function
> (assoc-from-hash ht)
> Lisp evaluates this as nil
>
> What I'm trying to get is a list of the form
> ((ANIMAL . DOG) (VEGETABLE . CARROT) (MINERAL . ZINC))
> but I can't get it to work.
>
> The reason's probably something very simple but I can't see it. Can
> anyone point out where I'm going wrong?
>
> In case it's pertinent, I'm using CLISP 2.38 with SLIME on Windows XP.
Without giving it away too easily ... the problem is that you assume a
particular function is destructive while it is in fact not. (You could
say that it's "pure functional clean.") If you used a destructive
version of the same function, it would work.
On a somewhat related note, (append assocList (list (cons k v))) feels
wasteful. A more common idiom is to push items onto the front of the
list and then destructively reverse it afterwards.
Ari Johnson <·········@gmail.com> writes:
> On a somewhat related note, (append assocList (list (cons k v))) feels
> wasteful. A more common idiom is to push items onto the front of the
> list and then destructively reverse it afterwards.
Actually, in this case [building the alist from a hash table], I doubt
that there is any need to reverse it afterwards. Entries in a hash table
aren't ordered in any particular way (and any ordering wouldn't even be
stable if the hash table grows), so it really doesn't matter what order
the values end up in in the returned association list.
--
Thomas A. Russ, USC/Information Sciences Institute
Ari Krupnik wrote:
> I have a class that has methods specialized on it that are
> expensive. I want to inherit from this class to include slots that can
> hold precomputed values of these expensive methods. I want to make it
> so that if I have an instance of the superclass, the expensive method
> will be called, but if I have an instance of the subclass, the slot
> value will be returned. I'm running into difficulties initializing the
> slots. I need to invoke the expensive method, but since I have a
> reference to the inheriting class, a call to to the function resolves
> to a reader method.
For things like this, I typically find the unbound slots machinery quite
useful. You can specialize slot-unbound, roughly like this:
(defmethod slot-unbound
((class t) (object myclass) (slot (eql 'my-slot)))
(setf (slot-value object 'my-slot)
(perform-expensive-computation ...)))
...and then leave the slot uninitialized. You can also force
recomputation by calling slot-makunbound.
It doesn't seem to exactly match your requirements, but maybe you find
this useful.
Pascal
--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
Pascal Costanza <··@p-cos.net> writes:
> For things like this, I typically find the unbound slots machinery
> quite useful. You can specialize slot-unbound, roughly like this:
>
> (defmethod slot-unbound
> ((class t) (object myclass) (slot (eql 'my-slot)))
> (setf (slot-value object 'my-slot)
> (perform-expensive-computation ...)))
>
> ...and then leave the slot uninitialized. You can also force
> recomputation by calling slot-makunbound.
>
> It doesn't seem to exactly match your requirements, but maybe you find
> this useful.
Quite. Thank you for pointing me in this direction. I looked up
slot-unbound in the hyperspec, and I don't understand the meaning of
the first argument. The class of the second argument is accessible
through type-of, so it must have some other significance.
Ari.
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
Ari Krupnik wrote:
> Pascal Costanza <··@p-cos.net> writes:
>
>> For things like this, I typically find the unbound slots machinery
>> quite useful. You can specialize slot-unbound, roughly like this:
>>
>> (defmethod slot-unbound
>> ((class t) (object myclass) (slot (eql 'my-slot)))
>> (setf (slot-value object 'my-slot)
>> (perform-expensive-computation ...)))
>>
>> ...and then leave the slot uninitialized. You can also force
>> recomputation by calling slot-makunbound.
>>
>> It doesn't seem to exactly match your requirements, but maybe you find
>> this useful.
>
> Quite. Thank you for pointing me in this direction. I looked up
> slot-unbound in the hyperspec, and I don't understand the meaning of
> the first argument. The class of the second argument is accessible
> through type-of, so it must have some other significance.
The first argument is only relevant when you use the CLOS MOP. Until
then you can safely ignore it, and just specialize it to 't, like in my
example above.
(The default behavior of slot-unbound is to signal an error. You can
change that default behavior for your own metaclass, and this is what
you need the first argument for, to specialize it on your own metaclass.
If this doesn't make sense to you, don't worry... ;)
Pascal
--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
Pascal Costanza <··@p-cos.net> writes:
>> Quite. Thank you for pointing me in this direction. I looked up
>> slot-unbound in the hyperspec, and I don't understand the meaning of
>> the first argument. The class of the second argument is accessible
>> through type-of, so it must have some other significance.
>
> The first argument is only relevant when you use the CLOS MOP. Until
> then you can safely ignore it, and just specialize it to 't, like in
> my example above.
>
> (The default behavior of slot-unbound is to signal an error. You can
> change that default behavior for your own metaclass, and this is what
> you need the first argument for, to specialize it on your own
> metaclass. If this doesn't make sense to you, don't worry... ;)
Thanks for the explanation. MOP looks like so much magic to me now,
but your post explained to me why I don't need to worry about the
argument until I learn MOP.
Ari.
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.