From: proton
Subject: CLOS constructors
Date: 
Message-ID: <638b3104-b53f-4ae9-9dd5-c1caf6914bae@d4g2000prg.googlegroups.com>
I am a newbie to CLOS and I'm wondering if the following is possible:
I want to have an initform for a slot which is a function of the value
of another slot. For example: I create a class with two slots, the
first one is initialized with a number, and the second slot should be
initialized with twice the value of the first slot, everytime I call
make-instance:

(defclass test ()
  ((slot0 :accessor slot0 :initform 3 :initarg :slot0)
   (slot1 :accessor slot1 :initform (* 2 slot0))))

(Obviously the above doesn't work)
How is it possible to do this? How can you refer to slots within the
same class? AFAIK this is possible with structures, so is CLOS more
limited?
TIA

From: Jason
Subject: Re: CLOS constructors
Date: 
Message-ID: <62ea02a4-3716-4a77-bf90-2e790b281960@b40g2000prf.googlegroups.com>
On Dec 10, 1:53 pm, proton <··········@gmail.com> wrote:
> I am a newbie to CLOS and I'm wondering if the following is possible:
> I want to have an initform for a slot which is a function of the value
> of another slot. For example: I create a class with two slots, the
> first one is initialized with a number, and the second slot should be
> initialized with twice the value of the first slot, everytime I call
> make-instance:
>
> (defclass test ()
>   ((slot0 :accessor slot0 :initform 3 :initarg :slot0)
>    (slot1 :accessor slot1 :initform (* 2 slot0))))
>
> (Obviously the above doesn't work)
> How is it possible to do this? How can you refer to slots within the
> same class? AFAIK this is possible with structures, so is CLOS more
> limited?
> TIA

see defmethod initialize-instance :after
From: proton
Subject: Re: CLOS constructors
Date: 
Message-ID: <f0224f9c-f8ec-4a9f-b4e1-d4af109157de@r60g2000hsc.googlegroups.com>
On Dec 10, 10:57 pm, Jason <·······@gmail.com> wrote:
> On Dec 10, 1:53 pm, proton <··········@gmail.com> wrote:
>
>
>
> > I am a newbie to CLOS and I'm wondering if the following is possible:
> > I want to have an initform for a slot which is a function of the value
> > of another slot. For example: I create a class with two slots, the
> > first one is initialized with a number, and the second slot should be
> > initialized with twice the value of the first slot, everytime I call
> > make-instance:
>
> > (defclass test ()
> >   ((slot0 :accessor slot0 :initform 3 :initarg :slot0)
> >    (slot1 :accessor slot1 :initform (* 2 slot0))))
>
> > (Obviously the above doesn't work)
> > How is it possible to do this? How can you refer to slots within the
> > same class? AFAIK this is possible with structures, so is CLOS more
> > limited?
> > TIA
>
> see defmethod initialize-instance :after

Thanks a lot. That was quick and right on target!
From: ········@comcast.net
Subject: Re: CLOS constructors
Date: 
Message-ID: <02fd555a-5ad5-483f-a1d8-9f96530a8313@e23g2000prf.googlegroups.com>
On Dec 10, 2:23 pm, proton <··········@gmail.com> wrote:
> On Dec 10, 10:57 pm, Jason <·······@gmail.com> wrote:
>
>
>
> > On Dec 10, 1:53 pm, proton <··········@gmail.com> wrote:
>
> > > I am a newbie to CLOS and I'm wondering if the following is possible:
> > > I want to have an initform for a slot which is a function of the value
> > > of another slot. For example: I create a class with two slots, the
> > > first one is initialized with a number, and the second slot should be
> > > initialized with twice the value of the first slot, everytime I call
> > > make-instance:
>
> > > (defclass test ()
> > >   ((slot0 :accessor slot0 :initform 3 :initarg :slot0)
> > >    (slot1 :accessor slot1 :initform (* 2 slot0))))
>
> > > (Obviously the above doesn't work)
> > > How is it possible to do this? How can you refer to slots within the
> > > same class? AFAIK this is possible with structures, so is CLOS more
> > > limited?
> > > TIA
>
> > see defmethod initialize-instance :after
>
> Thanks a lot. That was quick and right on target!

CLOS is really handy. It's not too big and not too small to do clever
stuff. In addition to the initialize-instance trick, there's
also a trick you can do with lazy evaluation; I do this frequently
with class definitions containing heavy calculations that you
don't want to evaluate at initialization time. Bear with me ... there
may be a few syntax glitches:

Define a class generic class:

(in-package :my-workspace)

(defclass product ()
  ((parent
    :initarg  :parent
    :reader   parent)
   (index
    :initarg :index
    :reader  index)))

;; I've added a few extra slots here; they're handy for establishing
product-structure.
;; If you define the slots against a special package (one where you
are unlikely have
;; function vs. generic function problems), you can avoid name-space
collisions. I
;; call mine "iv"...

(in-package :cl-user)

(defpackage "iv"
  (:nicknames :IV :iv "IV")
  (:use       :cl-user :ccl :cl))  ;; Mac Common Lisp -- got to cover
all the bases

;; Now redefine extended-class declaring the slot-names with the
package defined for
;; this purpose and make handing initialization arguments to the slots
optional:

(in-package :my-workspace) ;; or whatever your package is

(defclass product ()
  ((iv::parent
    :initarg  :parent
    :reader   iv::parent)
   (iv::index
    :initarg :index
    :reader  iv::index))
  (:default-initargs :parent nil :index nil))

;; Define a couple of lazy evaluation helper methods that retrieve the
cached
;; slot value or calculates, saves, and returns the value:

(defmethod eval-iv ((self product) (iv symbol) (rule function))
  (if (slot-exists-p self iv)
      (if (slot-boundp self iv)
          (slot-value self iv)
        (setf (slot-value self iv) (funcall rule self)))
    (error "No IV slot ~a exists for product instance ~a." iv self)))

(defmethod eval-iv ((self product) (iv symbol) (rule t))
  (if (slot-exists-p self iv)
      (if (slot-boundp self iv)
          (slot-value self iv)
        (setf (slot-value self iv) rule))
    (error "No IV slot ~a exists for product instance ~a." iv self)))

;; Now do something interesting with your class...

(defclass box (product)
  ((iv::depth  :initarg :depth  :reader iv::depth)
   (iv::width  :initarg :width  :reader iv::width)
   (iv::height :initarg :height :reader iv::height)
   (iv::volume)
   (iv::boxes))
  (:default-initargs :depth 1.0 :width 1.0 :height 1.0))

;; ...and define the reader/evaluator methods for the slots that don't
have a reader specified:

(defmethod iv::volume ((self box))
  (eval-iv
   self
   'iv::volume
   #'(lambda(self)(* (iv::depth self) (iv::width self) (iv::height
self)))))

;; The rule for this slot is volume = depth x width x height

(defmethod iv::boxes ((self box))
  (eval-iv
   self
   'iv::boxes
   #'(lambda(self)
       (mapcar
        #'(lambda(index)(make-instance 'box
                          :parent self
                          :index  index
                          :depth  (* (iv::depth self) 0.5)
                          :width  (* (iv::width self) 0.5)
                          :height (* (iv::height self) 0.5)))
       '(0 1 2)))))

;; The rule for this slot is: make 3 boxes with dimensions half the
size of the parent's dimensions.

;; Now try it:

(setq my-box (make-instance 'box :depth 2.0 :width 3.0 :height 4.0))

#<BOX #x9C27CA6>

;; At this point , slots iv::volume and iv::boxes are unbound.

(iv::volume my-box)

24.0

(iv::boxes my-box)

(#<BOX #x9D515CE> #<BOX #x9D528E6> #<BOX #x9D537B6>)


;; This is a stupid example and the class methods for volume and child
boxes are
;; implemented in a simplistic way for demo purposes, but you should
get the idea.
;; I have taken this step further and wrapped a macro around the whole
thing (defproduct)
;; in which I can define inputs, optional inputs, quantified child
products, descendant
;; slot values (all child products inherit the value from an
ancestor), and more
;; non-caching instance methods. I also define a macro called THIS
which implicitly
;; defines the SELF variable for the method expression so that you can
define the slot
;; method (the "rule") with a reference to the class instance itself
(which was your
;; original issue.) defmacro is your friend.

#'M
From: ··············@gmail.com
Subject: Re: CLOS constructors
Date: 
Message-ID: <d78d1330-5c83-482b-9904-8f268597fea0@w28g2000hsf.googlegroups.com>
> CLOS is really handy. It's not too big and not too small to do clever
> stuff. In addition to the initialize-instance trick, there's
> also a trick you can do with lazy evaluation; I do this frequently
> with class definitions containing heavy calculations that you
> don't want to evaluate at initialization time. Bear with me ... there
> may be a few syntax glitches:

http://common-lisp.net/project/computed-class/ does that transparently
as a MOP extension. cells, too.

- attila
From: Pascal Costanza
Subject: Re: CLOS constructors
Date: 
Message-ID: <5s71e2F17mhvkU1@mid.individual.net>
··············@gmail.com wrote:
>> CLOS is really handy. It's not too big and not too small to do clever
>> stuff. In addition to the initialize-instance trick, there's
>> also a trick you can do with lazy evaluation; I do this frequently
>> with class definitions containing heavy calculations that you
>> don't want to evaluate at initialization time. Bear with me ... there
>> may be a few syntax glitches:
> 
> http://common-lisp.net/project/computed-class/ does that transparently
> as a MOP extension. cells, too.

A pretty straightforward way is also this:

(defclass foo ()
   ((a :initarg :a :initform 0 :reader a)
    (b :reader b)))

(defmethod slot-unbound (class (object foo) (slot (eql 'b)))
   (setf (slot-value object 'b)
         (1+ (slot-value object 'a))))

 > (defvar *bar* (make-instance 'foo :a 5))
*BAR*

 > (b *bar*)
6

The nice thing about this is that you don't have to check for slot 
unboundness yourself, but can rely on the CLOS implementation to do this 
for you. This is probably more efficient than having calls for 
slot-boundp in your own code. You can also force recomputation by 
calling slot-makunbound on the respective slots. (I have used that 
technique in a few places, and it works like a charm.)

There is also a generic function slot-missing where you can do similar 
things for missing slots. For example, it is very straightforward to 
implement Python-style hashtable-based slots via slot-missing without 
having to go through the CLOS MOP at all this way.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Slobodan Blazeski
Subject: Re: CLOS constructors
Date: 
Message-ID: <ab249063-6bae-4087-940c-82bb6c3953d1@d21g2000prf.googlegroups.com>
On Dec 11, 9:52 am, Pascal Costanza <····@p-cos.net> wrote:
> ··············@gmail.com wrote:
> >> CLOS is really handy. It's not too big and not too small to do clever
> >> stuff. In addition to the initialize-instance trick, there's
> >> also a trick you can do with lazy evaluation; I do this frequently
> >> with class definitions containing heavy calculations that you
> >> don't want to evaluate at initialization time. Bear with me ... there
> >> may be a few syntax glitches:
>
> >http://common-lisp.net/project/computed-class/does that transparently
> > as a MOP extension. cells, too.
>
> A pretty straightforward way is also this:
>
> (defclass foo ()
>    ((a :initarg :a :initform 0 :reader a)
>     (b :reader b)))
>
> (defmethod slot-unbound (class (object foo) (slot (eql 'b)))
>    (setf (slot-value object 'b)
>          (1+ (slot-value object 'a))))
>
>  > (defvar *bar* (make-instance 'foo :a 5))
> *BAR*
>
>  > (b *bar*)
> 6
>
> The nice thing about this is that you don't have to check for slot
> unboundness yourself, but can rely on the CLOS implementation to do this
> for you. This is probably more efficient than having calls for
> slot-boundp in your own code. You can also force recomputation by
> calling slot-makunbound on the respective slots. (I have used that
> technique in a few places, and it works like a charm.)
>
> There is also a generic function slot-missing where you can do similar
> things for missing slots. For example, it is very straightforward to
> implement Python-style hashtable-based slots via slot-missing without
> having to go through the CLOS MOP at all this way.
>
> Pascal

Very nice trick, thank you Pascal.

Slobodan
http://tourdelisp.blogspot.com
>
> --
> My website:http://p-cos.net
> Common Lisp Document Repository:http://cdr.eurolisp.org
> Closer to MOP & ContextL:http://common-lisp.net/project/closer/
From: szergling
Subject: Re: CLOS constructors
Date: 
Message-ID: <96b5ab94-04d5-42a1-b23a-999103e70bd8@e10g2000prf.googlegroups.com>
On Dec 11, 9:52 pm, Pascal Costanza <····@p-cos.net> wrote:

[[ ... ]]

> >> also a trick you can do with lazy evaluation; I do this frequently
> >> with class definitions containing heavy calculations that you

[[ ... ]]

>
> A pretty straightforward way is also this:
>
> (defclass foo ()
>    ((a :initarg :a :initform 0 :reader a)
>     (b :reader b)))
>
> (defmethod slot-unbound (class (object foo) (slot (eql 'b)))
>    (setf (slot-value object 'b)
>          (1+ (slot-value object 'a))))
>
>  > (defvar *bar* (make-instance 'foo :a 5))
> *BAR*
>
>  > (b *bar*)
> 6
>
> The nice thing about this is that you don't have to check for slot
> unboundness yourself, but can rely on the CLOS implementation to do this
> for you. This is probably more efficient than having calls for
> slot-boundp in your own code. You can also force recomputation by
> calling slot-makunbound on the respective slots. (I have used that
> technique in a few places, and it works like a charm.)
>
> There is also a generic function slot-missing where you can do similar
> things for missing slots. For example, it is very straightforward to
> implement Python-style hashtable-based slots via slot-missing without
> having to go through the CLOS MOP at all this way.
>

Wow, this is cool. I didn't know this, but it
is so similar to the doesNotUnderstand message
for handling most "errors" in Smalltalk. I was
too slow, but was gonna suggest doing it with
a :before method. Not sure if it's better.

(defclass test ()
  ((a :accessor a
      :initarg :a)
   (b :accessor b
      :initarg :b)
   (lazy-product :accessor prod)))


(defmacro def-lazy-slot (accessor-name ((obj class) slot-name)  &body
body)
  `(defmethod ,accessor-name :before ((,obj ,class))
    (when (not (slot-boundp ,obj ',slot-name))
      (setf (slot-value ,obj ',slot-name)
            (progn
              ,@body)))))

(def-lazy-slot prod ((self test) lazy-product)
  (* (a self) (b self)))

which macroexpands to

(DEFMETHOD PROD :BEFORE ((SELF TEST))
  (WHEN (NOT (SLOT-BOUNDP SELF 'LAZY-PRODUCT))
    (SETF (SLOT-VALUE SELF 'LAZY-PRODUCT)
          (PROGN (* (A SELF) (B SELF))))))
From: Thomas F. Burdick
Subject: Re: CLOS constructors
Date: 
Message-ID: <d02dced8-16f4-49a6-85e2-c11f4768319c@p69g2000hsa.googlegroups.com>
On Dec 11, 10:27 am, szergling <···············@gmail.com> wrote:
> On Dec 11, 9:52 pm, Pascal Costanza <····@p-cos.net> wrote:

> > There is also a generic function slot-missing where you can do similar
> > things for missing slots. For example, it is very straightforward to
> > implement Python-style hashtable-based slots via slot-missing without
> > having to go through the CLOS MOP at all this way.
>
> Wow, this is cool. I didn't know this, but it
> is so similar to the doesNotUnderstand message
> for handling most "errors" in Smalltalk.

Yes, slot-missing and slot-unbound are kind of like doesNotUnderstand
for slot access.  no-applicable-method is even more like
doesNotUnderstand in that it gives you a hook into the machinery where
no method was found; however, due partly to the way CLOS generic
functions work, and partly to its design, it's not an especially
useful hook.
From: Pascal Costanza
Subject: Re: CLOS constructors
Date: 
Message-ID: <5s7a9sF17p0sfU1@mid.individual.net>
Thomas F. Burdick wrote:
> On Dec 11, 10:27 am, szergling <···············@gmail.com> wrote:
>> On Dec 11, 9:52 pm, Pascal Costanza <····@p-cos.net> wrote:
> 
>>> There is also a generic function slot-missing where you can do similar
>>> things for missing slots. For example, it is very straightforward to
>>> implement Python-style hashtable-based slots via slot-missing without
>>> having to go through the CLOS MOP at all this way.
>> Wow, this is cool. I didn't know this, but it
>> is so similar to the doesNotUnderstand message
>> for handling most "errors" in Smalltalk.
> 
> Yes, slot-missing and slot-unbound are kind of like doesNotUnderstand
> for slot access.  no-applicable-method is even more like
> doesNotUnderstand in that it gives you a hook into the machinery where
> no method was found; however, due partly to the way CLOS generic
> functions work, and partly to its design, it's not an especially
> useful hook.

My impression is that these hooks were not so much driven by utility, 
but rather by the fact that CLOS and the condition system were developed 
independently from each other at more or less the same time. Since the 
CLOS designers didn't have an API for signalling errors, they reverted 
to generic functions doing that job for them, and whose details could be 
defined later.

In the case of slot-unbound and slot-missing, this 'accidentally' 
resulted in a pretty useful hook.

Of course, I am only guessing here. The ANSI CL standardization 
committee members may be able to say whether my guess is right or not...


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Nicolas Neuss
Subject: Re: CLOS constructors
Date: 
Message-ID: <87prxdfnad.fsf@ma-patru.mathematik.uni-karlsruhe.de>
"Thomas F. Burdick" <········@gmail.com> writes:

> Yes, slot-missing and slot-unbound are kind of like doesNotUnderstand
> for slot access.  no-applicable-method is even more like
> doesNotUnderstand in that it gives you a hook into the machinery where
> no method was found; however, due partly to the way CLOS generic
> functions work, and partly to its design, it's not an especially
> useful hook.

May I ask why?

Nicolas
From: Pascal Costanza
Subject: Re: CLOS constructors
Date: 
Message-ID: <5s7hc1F17sjtfU1@mid.individual.net>
Nicolas Neuss wrote:
> "Thomas F. Burdick" <········@gmail.com> writes:
> 
>> Yes, slot-missing and slot-unbound are kind of like doesNotUnderstand
>> for slot access.  no-applicable-method is even more like
>> doesNotUnderstand in that it gives you a hook into the machinery where
>> no method was found; however, due partly to the way CLOS generic
>> functions work, and partly to its design, it's not an especially
>> useful hook.
> 
> May I ask why?

The only thing you can specialize on in no-applicable-method and 
no-next-method are the respective generic function and, in the latter 
case, the method from which the call was attempted. This is potentially 
useful if you implement your own extensions based on the CLOS MOP, but 
from the base-level CLOS, you may as well just define an unspecialized 
method.

Also, there is no no-primary-method, which could have been useful. Alas, 
you can cover these and more cases with define-method-combination.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: szergling
Subject: Re: CLOS constructors
Date: 
Message-ID: <30c1f3f2-2539-4c24-93d8-4bcf7931c056@b1g2000pra.googlegroups.com>
On Dec 12, 2:24 am, Pascal Costanza <····@p-cos.net> wrote:
> Nicolas Neuss wrote:
> > "Thomas F. Burdick" <········@gmail.com> writes:
>
> >> Yes, slot-missing and slot-unbound are kind of like doesNotUnderstand
> >> for slot access.  no-applicable-method is even more like
> >> doesNotUnderstand in that it gives you a hook

Thanks for all the replies.

A bunch of very interesting discussions. I think I'll
re-read AMOP again paying attention to thread-safety
issues this time (alluded to in an earlier post).

There're many new ideas I did not think of before
here. Keep 'em coming!
From: Nicolas Neuss
Subject: Re: CLOS constructors
Date: 
Message-ID: <87abohfdok.fsf@ma-patru.mathematik.uni-karlsruhe.de>
Pascal Costanza <··@p-cos.net> writes:

> Nicolas Neuss wrote:
>> "Thomas F. Burdick" <········@gmail.com> writes:
>>
>>> Yes, slot-missing and slot-unbound are kind of like doesNotUnderstand
>>> for slot access.  no-applicable-method is even more like
>>> doesNotUnderstand in that it gives you a hook into the machinery where
>>> no method was found; however, due partly to the way CLOS generic
>>> functions work, and partly to its design, it's not an especially
>>> useful hook.
>>
>> May I ask why?
>
> The only thing you can specialize on in no-applicable-method and
> no-next-method are the respective generic function and, in the latter case,
> the method from which the call was attempted. This is potentially useful if
> you implement your own extensions based on the CLOS MOP, but from the
> base-level CLOS, you may as well just define an unspecialized method.
>
> Also, there is no no-primary-method, which could have been useful. Alas,
> you can cover these and more cases with define-method-combination.
>
> Pascal

OK, maybe there could be a more useful interface.  I only want to note that
I have found NO-APPLICABLE-METHOD to be useful in the following way:

(defun extend-matlisp-function (func)
    (defmethod no-applicable-method ((gf (eql func)) &rest args)
       ...))

which extends (on demand) a generic function defined on Matlisp matrices to
work also with another class of matrices.

Nicolas
From: Pascal Costanza
Subject: Re: CLOS constructors
Date: 
Message-ID: <5s87ngF17glj9U1@mid.individual.net>
Nicolas Neuss wrote:

> OK, maybe there could be a more useful interface.  I only want to note that
> I have found NO-APPLICABLE-METHOD to be useful in the following way:
> 
> (defun extend-matlisp-function (func)
>     (defmethod no-applicable-method ((gf (eql func)) &rest args)
>        ...))
> 
> which extends (on demand) a generic function defined on Matlisp matrices to
> work also with another class of matrices.

Hm, wouldn't it be better to directly define a method on the respective 
generic function ('func in this example)?


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Nicolas Neuss
Subject: Re: CLOS constructors
Date: 
Message-ID: <877ijkdy5x.fsf@ma-patru.mathematik.uni-karlsruhe.de>
Pascal Costanza <··@p-cos.net> writes:

> Nicolas Neuss wrote:
>
>> OK, maybe there could be a more useful interface.  I only want to note that
>> I have found NO-APPLICABLE-METHOD to be useful in the following way:
>>
>> (defun extend-matlisp-function (func)
>>     (defmethod no-applicable-method ((gf (eql func)) &rest args)
>>        ...))
>>
>> which extends (on demand) a generic function defined on Matlisp matrices to
>> work also with another class of matrices.
>
> Hm, wouldn't it be better to directly define a method on the respective
> generic function ('func in this example)?
>
> Pascal

No, because

1. Ease of use.  Here I do not have to know the precise signature of the
gf and can use it as: (extend-matlisp-function #'matlisp::fft)

2. Different functionality: for my approach, my branch is only taken when
all other methods fail (e.g. the Matlisp library might itself specify a
method for the most general case working around the missing method).

Maybe I should have posted the whole function before (I have appended it
now).

Yours, Nicolas


(defun extend-matlisp-function (func)
  "If @package{MATLISP} is available, and the argument @arg{func} is a
generic function in this package, this function is extended to be
applicable to matrices in @arg{FL.MATLISP}.  This is done by defining a
method for @function{no-applicable-method} which converts the arguments,
calls @arg{func} and reconverts the returned values.  If @package{MATLISP}
is not available, NIL is returned."
  (whereas ((matlisp-package (find-package "MATLISP")))
    (when (and (typep func 'generic-function)
	       (eq (symbol-package (fl.amop::generic-function-name func))
		   matlisp-package))
      (destructuring-bind (standard-matrix real-matrix complex-matrix
					   nrows ncols store)
	  (mapcar (rcurry #'intern matlisp-package)
		  '("STANDARD-MATRIX" "REAL-MATRIX" "COMPLEX-MATRIX"
		    "NROWS" "NCOLS" "STORE"))
	(defmethod no-applicable-method ((gf (eql func)) &rest args)
	  (let (alist)
	    ;; setup translation table with arguments
	    (loop for obj in args do
		 (when (and (typep obj 'fl.matlisp:standard-matrix)
			    (not (assoc obj alist)))
		   (push
		    (cons obj
			  (if (eq (element-type obj) 'double-float)
			      (make-instance real-matrix
					     :nrows (nrows obj) :ncols (ncols obj) :store (store obj))
			      (make-instance complex-matrix
					     :nrows (nrows obj) :ncols (ncols obj) :store
					     (complex-to-real-vector (store obj)))))
		    alist)))
	    (unless alist
	      (error "No matching method for the generic function ~S, when called with arguments ~S."
		     gf args))
	    (let ((return-values
		   (multiple-value-list
		    (apply gf (loop for obj in args collect
				   (or (geta alist obj) obj))))))
	      ;; augment translation table with returned values
	      (loop for obj in return-values do
		   (when (and (typep obj standard-matrix)
			      (not (rassoc obj alist)))
		     (push (cons (make-instance (fl.matlisp:standard-matrix
						 (cond ((typep obj real-matrix) 'double-float)
						       ((typep obj complex-matrix) '(complex double-float))
						       (t (error "Unknown Matlisp matrix."))))
						:nrows (funcall nrows obj) :ncols (funcall ncols obj)
						:store (let ((store (funcall store obj)))
							 (if (typep obj real-matrix)
							     store
							     (real-to-complex-vector store))))
				 obj)
			   alist)))
	      (apply #'values (loop for obj in return-values collect
				   (or (car (rassoc obj alist)) obj))))))))))
From: Pascal Costanza
Subject: Re: CLOS constructors
Date: 
Message-ID: <5saq6bF154ml0U1@mid.individual.net>
Nicolas Neuss wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>> Nicolas Neuss wrote:
>>
>>> OK, maybe there could be a more useful interface.  I only want to note that
>>> I have found NO-APPLICABLE-METHOD to be useful in the following way:
>>>
>>> (defun extend-matlisp-function (func)
>>>     (defmethod no-applicable-method ((gf (eql func)) &rest args)
>>>        ...))
>>>
>>> which extends (on demand) a generic function defined on Matlisp matrices to
>>> work also with another class of matrices.
>> Hm, wouldn't it be better to directly define a method on the respective
>> generic function ('func in this example)?
>>
>> Pascal
> 
> No, because
> 
> 1. Ease of use.  Here I do not have to know the precise signature of the
> gf and can use it as: (extend-matlisp-function #'matlisp::fft)
> 
> 2. Different functionality: for my approach, my branch is only taken when
> all other methods fail (e.g. the Matlisp library might itself specify a
> method for the most general case working around the missing method).
> 
> Maybe I should have posted the whole function before (I have appended it
> now).

OK, thanks. That's interesting...

Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: CLOS constructors
Date: 
Message-ID: <5saramF16fj8oU2@mid.individual.net>
Pascal Costanza wrote:
> Nicolas Neuss wrote:
>> Pascal Costanza <··@p-cos.net> writes:
>>
>>> Nicolas Neuss wrote:
>>>
>>>> OK, maybe there could be a more useful interface.  I only want to 
>>>> note that
>>>> I have found NO-APPLICABLE-METHOD to be useful in the following way:
>>>>
>>>> (defun extend-matlisp-function (func)
>>>>     (defmethod no-applicable-method ((gf (eql func)) &rest args)
>>>>        ...))
>>>>
>>>> which extends (on demand) a generic function defined on Matlisp 
>>>> matrices to
>>>> work also with another class of matrices.
>>> Hm, wouldn't it be better to directly define a method on the respective
>>> generic function ('func in this example)?
>>>
>>> Pascal
>>
>> No, because
>>
>> 1. Ease of use.  Here I do not have to know the precise signature of the
>> gf and can use it as: (extend-matlisp-function #'matlisp::fft)
>>
>> 2. Different functionality: for my approach, my branch is only taken when
>> all other methods fail (e.g. the Matlisp library might itself specify a
>> method for the most general case working around the missing method).
>>
>> Maybe I should have posted the whole function before (I have appended it
>> now).
> 
> OK, thanks. That's interesting...

Ah, now I know why I am having doubts. Specializing on a single function 
the way you do it is actually not supported by ANSI CL. See bullet 19 in 
  Section 11.1.2.1.2 of the HyperSpec (which I think is too strict, I 
should this kind of specialization should actually be supported).

Well, if it works, it works. ;)


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Nicolas Neuss
Subject: Re: CLOS constructors
Date: 
Message-ID: <87ejdrfylr.fsf@ma-patru.mathematik.uni-karlsruhe.de>
Pascal Costanza <··@p-cos.net> writes:

>>> No, because
>>>
>>> 1. Ease of use.  Here I do not have to know the precise signature of the
>>> gf and can use it as: (extend-matlisp-function #'matlisp::fft)
>>>
>>> 2. Different functionality: for my approach, my branch is only taken when
>>> all other methods fail (e.g. the Matlisp library might itself specify a
>>> method for the most general case working around the missing method).
>>>
>>> Maybe I should have posted the whole function before (I have appended it
>>> now).
>>
>> OK, thanks. That's interesting...
>
> Ah, now I know why I am having doubts. Specializing on a single function
> the way you do it is actually not supported by ANSI CL. See bullet 19 in
> Section 11.1.2.1.2 of the HyperSpec (which I think is too strict, I
> should this kind of specialization should actually be supported).
>
> Well, if it works, it works. ;)

Hmm, of course, one could extend every generic function which turns out to
lie in the Matlisp package.

But I have also gotten doubts about my approach, out of a different reason.
It does not scale.  I.e. if some other library tries to use the same idea
to extend Matlisp generic functions, it would break.  Of course, it is even
more probable to run into problems if one cannot specialize on single
generic functions.

So, I think that I now agree with you and Thomas about the usefulness of
NO-APPLICABLE-METHOD.  At least, my use of NO-APPLICABLE-METHOD is not very
convincing.

Nicolas
From: Thomas F. Burdick
Subject: Re: CLOS constructors
Date: 
Message-ID: <746aabd9-f299-4b14-b9c4-d61feddeabe6@i29g2000prf.googlegroups.com>
On Dec 12, 9:26 pm, Nicolas Neuss <········@math.uni-karlsruhe.de>
wrote:
> Pascal Costanza <····@p-cos.net> writes:
> >>> No, because
>
> >>> 1. Ease of use.  Here I do not have to know the precise signature of the
> >>> gf and can use it as: (extend-matlisp-function #'matlisp::fft)
>
> >>> 2. Different functionality: for my approach, my branch is only taken when
> >>> all other methods fail (e.g. the Matlisp library might itself specify a
> >>> method for the most general case working around the missing method).
>
> >>> Maybe I should have posted the whole function before (I have appended it
> >>> now).
>
> >> OK, thanks. That's interesting...
>
> > Ah, now I know why I am having doubts. Specializing on a single function
> > the way you do it is actually not supported by ANSI CL. See bullet 19 in
> > Section 11.1.2.1.2 of the HyperSpec (which I think is too strict, I
> > should this kind of specialization should actually be supported).
>
> > Well, if it works, it works. ;)
>
> Hmm, of course, one could extend every generic function which turns out to
> lie in the Matlisp package.
>
> But I have also gotten doubts about my approach, out of a different reason.
> It does not scale.  I.e. if some other library tries to use the same idea
> to extend Matlisp generic functions, it would break.  Of course, it is even
> more probable to run into problems if one cannot specialize on single
> generic functions.
>
> So, I think that I now agree with you and Thomas about the usefulness of
> NO-APPLICABLE-METHOD.  At least, my use of NO-APPLICABLE-METHOD is not very
> convincing.

For what it's worth, I think you could accomplish what you want to do
with the reflective MOP and add-method.  Which, incidentally, isn't
unlike the other ST approach: write a program to write the delegation
methods for you.
From: Thomas F. Burdick
Subject: Re: CLOS constructors
Date: 
Message-ID: <b45ed8c1-c6d4-45c4-9673-861450c21644@d27g2000prf.googlegroups.com>
On Dec 11, 4:34 pm, Nicolas Neuss <········@math.uni-karlsruhe.de>
wrote:
> Pascal Costanza <····@p-cos.net> writes:
> > Nicolas Neuss wrote:
> >> "Thomas F. Burdick" <········@gmail.com> writes:
>
> >>> Yes, slot-missing and slot-unbound are kind of like doesNotUnderstand
> >>> for slot access.  no-applicable-method is even more like
> >>> doesNotUnderstand in that it gives you a hook into the machinery where
> >>> no method was found; however, due partly to the way CLOS generic
> >>> functions work, and partly to its design, it's not an especially
> >>> useful hook.
>
> >> May I ask why?
>
> > The only thing you can specialize on in no-applicable-method and
> > no-next-method are the respective generic function and, in the latter case,
> > the method from which the call was attempted. This is potentially useful if
> > you implement your own extensions based on the CLOS MOP, but from the
> > base-level CLOS, you may as well just define an unspecialized method.

That's more or less my point right there.  And also that it would have
been pretty easy to have n-a-m in turn use a protocol to allow
dispatching based on the arguments to the function call, which is
needed to do the myriad useful things that smalltalkers use DNU for.
Like making proxy objects or automating the process of dispatching
certain protocols to delegates.  Or the withWithWith... pattern, which
is sort of like being able to make cxx...xxr work on-demand for any
number of a's and d's (and it's about as dubious :)

> > Also, there is no no-primary-method, which could have been useful. Alas,
> > you can cover these and more cases with define-method-combination.
>
> > Pascal
>
> OK, maybe there could be a more useful interface.  I only want to note that
> I have found NO-APPLICABLE-METHOD to be useful in the following way:
>
> (defun extend-matlisp-function (func)
>     (defmethod no-applicable-method ((gf (eql func)) &rest args)
>        ...))
>
> which extends (on demand) a generic function defined on Matlisp matrices to
> work also with another class of matrices.

As Pascal already noted, this doesn't buy you anything compared to
just defining the methods on the gf directly.
From: Pascal Costanza
Subject: Re: CLOS constructors
Date: 
Message-ID: <5s76eeF17jdhhU1@mid.individual.net>
szergling wrote:
> On Dec 11, 9:52 pm, Pascal Costanza <····@p-cos.net> wrote:
> 
> [[ ... ]]
> 
>>>> also a trick you can do with lazy evaluation; I do this frequently
>>>> with class definitions containing heavy calculations that you
> 
> [[ ... ]]
> 
>> A pretty straightforward way is also this:
>>
>> (defclass foo ()
>>    ((a :initarg :a :initform 0 :reader a)
>>     (b :reader b)))
>>
>> (defmethod slot-unbound (class (object foo) (slot (eql 'b)))
>>    (setf (slot-value object 'b)
>>          (1+ (slot-value object 'a))))
>>
>>  > (defvar *bar* (make-instance 'foo :a 5))
>> *BAR*
>>
>>  > (b *bar*)
>> 6
>>
>> The nice thing about this is that you don't have to check for slot
>> unboundness yourself, but can rely on the CLOS implementation to do this
>> for you. This is probably more efficient than having calls for
>> slot-boundp in your own code. You can also force recomputation by
>> calling slot-makunbound on the respective slots. (I have used that
>> technique in a few places, and it works like a charm.)
>>
>> There is also a generic function slot-missing where you can do similar
>> things for missing slots. For example, it is very straightforward to
>> implement Python-style hashtable-based slots via slot-missing without
>> having to go through the CLOS MOP at all this way.
>>
> 
> Wow, this is cool. I didn't know this, but it
> is so similar to the doesNotUnderstand message
> for handling most "errors" in Smalltalk. I was
> too slow, but was gonna suggest doing it with
> a :before method. Not sure if it's better.
> 
> (defclass test ()
>   ((a :accessor a
>       :initarg :a)
>    (b :accessor b
>       :initarg :b)
>    (lazy-product :accessor prod)))
> 
> 
> (defmacro def-lazy-slot (accessor-name ((obj class) slot-name)  &body
> body)
>   `(defmethod ,accessor-name :before ((,obj ,class))
>     (when (not (slot-boundp ,obj ',slot-name))
>       (setf (slot-value ,obj ',slot-name)
>             (progn
>               ,@body)))))
> 
> (def-lazy-slot prod ((self test) lazy-product)
>   (* (a self) (b self)))
> 
> which macroexpands to
> 
> (DEFMETHOD PROD :BEFORE ((SELF TEST))
>   (WHEN (NOT (SLOT-BOUNDP SELF 'LAZY-PRODUCT))
>     (SETF (SLOT-VALUE SELF 'LAZY-PRODUCT)
>           (PROGN (* (A SELF) (B SELF))))))

Well, there are two things to note:

- Whenever you call slot-value or a reader on a slot, CLOS has to do the 
unboundness check anyway. So idioms like (and (slot-boundp object 
some-slot) (slot-value object some-slot)) actually result in two checks 
for unboundness, which is not so efficient.

- Reader methods are especially optimized to yield fast slot accesses. I 
don't know what impact before/after/around on slot accessors actually 
have in terms of performance, but I'd be careful here.

- Methods on slot-unbound avoid all these potential performance issues 
from the start.

There is also a potential problem wrt to multi-threading: In between 
your own slot-boundp check and the eventual call to slot-value, another 
thread might perform a slot-makunbound on the slot in question. In 
general, it is better not to perform such checks explicitly, but rather 
delegate this to an implicit check where you can react to exceptional 
situations where your assumptions don't hold. (Methods on slot-unbound 
are an example for this.) This should help you to better avoid race 
conditions.

This is only a hypothetical remark, though, since CLOS and 
multithreading don't go that well together, and you have to be more 
careful than that anyway...


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ········@comcast.net
Subject: Re: CLOS constructors
Date: 
Message-ID: <33976bc3-a34f-46c5-899c-6917c9acfe04@e23g2000prf.googlegroups.com>
On Dec 11, 12:52 am, Pascal Costanza <····@p-cos.net> wrote:
> ··············@gmail.com wrote:
> >> CLOS is really handy. It's not too big and not too small to do clever
> >> stuff. In addition to the initialize-instance trick, there's
> >> also a trick you can do with lazy evaluation; I do this frequently
> >> with class definitions containing heavy calculations that you
> >> don't want to evaluate at initialization time. Bear with me ... there
> >> may be a few syntax glitches:
>
> >http://common-lisp.net/project/computed-class/does that transparently
> > as a MOP extension. cells, too.
>
> A pretty straightforward way is also this:
>
> (defclass foo ()
>    ((a :initarg :a :initform 0 :reader a)
>     (b :reader b)))
>
> (defmethod slot-unbound (class (object foo) (slot (eql 'b)))
>    (setf (slot-value object 'b)
>          (1+ (slot-value object 'a))))
>
>  > (defvar *bar* (make-instance 'foo :a 5))
> *BAR*
>
>  > (b *bar*)
> 6
>
> The nice thing about this is that you don't have to check for slot
> unboundness yourself, but can rely on the CLOS implementation to do this
> for you. This is probably more efficient than having calls for
> slot-boundp in your own code. You can also force recomputation by
> calling slot-makunbound on the respective slots. (I have used that
> technique in a few places, and it works like a charm.)
>
> There is also a generic function slot-missing where you can do similar
> things for missing slots. For example, it is very straightforward to
> implement Python-style hashtable-based slots via slot-missing without
> having to go through the CLOS MOP at all this way.
>
> Pascal
>
> --
> My website:http://p-cos.net
> Common Lisp Document Repository:http://cdr.eurolisp.org
> Closer to MOP & ContextL:http://common-lisp.net/project/closer/

This is all great. I recommend these newsgroups to folks just getting
into the business. Big thanks to everyone.

Pascal's check-before-firing technique that extends slot-unbound
accomplishes the same thing with fewer steps illustrating the process.
His mechanism is self-contained and closer to what I do in practice
(e.g., what someone pays for.)

The goal behind the code pieces that I posted was the avoidance of
firing the rule behind the method every time you call it by checking
for its value existence. If you've ever implemented a surfaces or
solids package, then you know what I mean. Otherwise, the straight-
forward solution of setting values in an extension of initialize-
instance is the way to go.

For green Lispers:

Don't try to optimize your code before you get your application
running (preoptimization is the path to failure.) Don't worry about
what tool in Lisp is more or less efficient; it all works. Results
matter. So does the learning experience. Do what makes the job easier
for you, not the Lisp enviro. Later, throw a time wrapper around
things and see what you can fiddle with. Once you have some time in
the saddle, try to build yourself a toolset where you spend less time
thinking about code and more time thinking about the problem you are
trying to solve.

M
From: Dimiter "malkia" Stanev
Subject: Re: CLOS constructors
Date: 
Message-ID: <5s8arnF16jbn2U1@mid.individual.net>
> For green Lispers:
> 
> Don't try to optimize your code before you get your application
> running (preoptimization is the path to failure.) Don't worry about
> what tool in Lisp is more or less efficient; it all works. Results
> matter. So does the learning experience. Do what makes the job easier
> for you, not the Lisp enviro. Later, throw a time wrapper around
> things and see what you can fiddle with. Once you have some time in
> the saddle, try to build yourself a toolset where you spend less time
> thinking about code and more time thinking about the problem you are
> trying to solve.

A green lisper thanks you for the advice! But really the first time I've 
used Common Lisp I just had to start straight from the optimizations 
just to see what the language is capable in terms of power... Once I've 
got a couple of performance tests, and it proved to me that at worst it 
can be 2 maximum 3 times slower than C (and this was code translated by 
me hand-by-hand - one handling data compression, the other one floating 
point arithmetic). Now I can go back and just set (debug 3) (optimize 0) 
and be glad. Later when I found how to use the profiler, I'll know that 
I'll be able to optimize.

I think that's the important piece - with Common Lisp - I know there 
exist implementation, and way to make your code fast if you need to. 
With other script languages - I either have to rewrite code back to "C", 
or wait for their new magical/special VM's to come.