From: William Bland
Subject: Is this the Right Thing?
Date: 
Message-ID: <pan.2004.11.06.00.59.16.195129@abstractnonsense.com>
I'm still to new to CLOS to know if this is the Right Thing, or just an
ugly hack.

I was thinking of ways of making class hierarchies and defining methods on
them, in the case where you *always* want to call the method that
specialises on the superclass as well as the one that specialises on the
class at hand.  You could use CALL-NEXT-METHOD, but then you have to
remember to do it every time you define a new subclass and a method
specialising on it.

The solution (hack?) I came up with was:

(defclass shape ()
  ((mass :initform 0 :initarg :mass)))

(defclass circle (shape)
  ((x :initform 0 :initarg :x)
   (y :initform 0 :initarg :x)
   (radius :initform 0 :initarg :radius)))

(defclass square (shape)
  ((x :initform 0 :initarg :x)
   (y :initform 0 :initarg :y)
   (width :initform 0 :initarg :width)))

(defgeneric check (arg))

(defmethod check :before ((arg shape))
  ; everything that inherits from shape needs its mass checking
  (assert (> (slot-value arg 'mass) 0)))

(defmethod check ((arg shape))
  nil) ; nothing else to check

(defmethod check ((arg circle))
  (assert (> (slot-value arg 'radius) 0)))

(defmethod check ((arg square))
  (assert (> (slot-value arg 'width) 0)))

So is that a normal thing to do?  Is there any reason why it's not good
form?  Is there a much better way that I've completely overlooked?

The reason I was thinking about this is that I really wanted to do the
same thing in one of our Java programs at work, but I can see no way to
achieve the same thing in Java.  I'll just have to tell everyone "remember
to call super.foo() whenever you subclass and override foo".

Cheers,
	Bill.
-- 
"If you give someone Fortran, he has Fortran. If you give someone Lisp,
he has any language he pleases." -- Guy Steele

From: Brian Downing
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <4PVid.50473$HA.4083@attbi_s01>
In article <······························@abstractnonsense.com>,
William Bland  <·······@abstractnonsense.com> wrote:
> I was thinking of ways of making class hierarchies and defining methods on
> them, in the case where you *always* want to call the method that
> specialises on the superclass as well as the one that specialises on the
> class at hand.  You could use CALL-NEXT-METHOD, but then you have to
> remember to do it every time you define a new subclass and a method
> specialising on it.

> So is that a normal thing to do?  Is there any reason why it's not good
> form?  Is there a much better way that I've completely overlooked?

The most "non-kludgey" way I can think of is to use the PROGN method
combination.  That spells out clearly what you're trying to accomplish.

Unfortunatly, it runs most-specific-first:

(defgeneric check (arg)
  (:method-combination progn))

(defmethod check progn ((arg shape))  (print "Checking SHAPE"))
(defmethod check progn ((arg circle)) (print "Checking CIRCLE"))
(defmethod check progn ((arg square)) (print "Checking SQUARE"))

CL-USER> (check (make-instance 'square))
"Checking SQUARE" 
"Checking SHAPE" 

A way to get the other order, but seems more kludgey to me, is to have a
null primary method on SHAPE and then have all your checks in :AFTER
methods:

(defgeneric check (arg)
  (:method ((arg shape)) nil))

(defmethod check :after ((arg shape))  (print "Checking SHAPE")) 
(defmethod check :after ((arg circle)) (print "Checking CIRCLE")) 
(defmethod check :after ((arg square)) (print "Checking SQUARE"))

CL-USER> (check (make-instance 'square))
"Checking SHAPE" 
"Checking SQUARE" 

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: Tim Bradshaw
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <ey3d5yr1bik.fsf@cley.com>
* Brian Downing wrote:

> The most "non-kludgey" way I can think of is to use the PROGN method
> combination.  That spells out clearly what you're trying to accomplish.

> Unfortunatly, it runs most-specific-first:

Not necessarily!

(defgeneric foo (x)
  (:method-combination progn :most-specific-last))

--tim
From: Kenneth Tilton
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <ktilton-A0C403.12215106112004@nyctyp01-ge0.rdc-nyc.rr.com>
In article <···············@cley.com>, Tim Bradshaw <···@cley.com> 
wrote:

> * Brian Downing wrote:
> 
> > The most "non-kludgey" way I can think of is to use the PROGN method
> > combination.  That spells out clearly what you're trying to accomplish.
> 
> > Unfortunatly, it runs most-specific-first:
> 
> Not necessarily!
> 
> (defgeneric foo (x)
>   (:method-combination progn :most-specific-last))
> 
> --tim

Omigod! <g>

kenny
From: Brian Downing
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <Oc8jd.472255$mD.253279@attbi_s02>
In article <···············@cley.com>, Tim Bradshaw  <···@cley.com> wrote:
> * Brian Downing wrote:
> 
> > The most "non-kludgey" way I can think of is to use the PROGN method
> > combination.  That spells out clearly what you're trying to accomplish.
> 
> > Unfortunatly, it runs most-specific-first:
> 
> Not necessarily!
> 
> (defgeneric foo (x)
>   (:method-combination progn :most-specific-last))

Sweet!  CLOS rocks!  :)

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: William Bland
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <pan.2004.11.06.20.00.14.827595@abstractnonsense.com>
On Sat, 06 Nov 2004 11:07:31 +0000, Tim Bradshaw wrote:

> * Brian Downing wrote:
> 
>> The most "non-kludgey" way I can think of is to use the PROGN method
>> combination.  That spells out clearly what you're trying to accomplish.
> 
>> Unfortunatly, it runs most-specific-first:
> 
> Not necessarily!
> 
> (defgeneric foo (x)
>   (:method-combination progn :most-specific-last))
> 

Cool!  Thanks very much to all who replied.

I'm still not sure about one thing though:

If the DEFGENERIC, we say that we want the method combination for this
generic function to be PROGN.  Why do we have to then effectively repeat
this information in each DEFMETHOD?

I had a quick look at the HyperSpec section on DEFINE-METHOD-COMBINATION,
and it looked to me like this duplication of information could have been
avoided if the PROGN method combination was defined using the long form of
DEFINE-METHOD-COMBINATION.  Presumably there's a good reason not to do it
that way?

Cheers,
	Bill.
-- 
"If you give someone Fortran, he has Fortran. If you give someone Lisp,
he has any language he pleases." -- Guy Steele
From: Steven M. Haflich
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <e9bjd.39163$QJ3.6348@newssvr21.news.prodigy.com>
William Bland wrote:

> I'm still not sure about one thing though:
> 
> If the DEFGENERIC, we say that we want the method combination for this
> generic function to be PROGN.  Why do we have to then effectively repeat
> this information in each DEFMETHOD?

A generic function is a single function.  But it is a single function
whose definition is typically spread among many defining forms, possibly
spread between several files.  This raises unfamiliar issues managing
modularity and achieving understandable, readable, and maintainable
code.

The redundancy of the :progn specification improves both readability and
error detection.  This is especially true if all the methods are not
gathered together in the same place in the source.  Anyone reading any
part of the code is clued into how he function works.
From: William Bland
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <pan.2004.11.06.22.09.17.559392@abstractnonsense.com>
On Sat, 06 Nov 2004 21:14:50 +0000, Steven M. Haflich wrote:

> William Bland wrote:
> 
>> I'm still not sure about one thing though:
>> 
>> If the DEFGENERIC, we say that we want the method combination for this
>> generic function to be PROGN.  Why do we have to then effectively repeat
>> this information in each DEFMETHOD?
> 
> A generic function is a single function.  But it is a single function
> whose definition is typically spread among many defining forms, possibly
> spread between several files.  This raises unfamiliar issues managing
> modularity and achieving understandable, readable, and maintainable
> code.
> 
> The redundancy of the :progn specification improves both readability and
> error detection.  This is especially true if all the methods are not
> gathered together in the same place in the source.  Anyone reading any
> part of the code is clued into how he function works.

Sure, understood.  I was still worried about this for a while though,
until I had a minor epiphany just now:  It doesn't matter that the
information is duplicated, because if you change it in one place (e.g. you
decide on a different combination in the DEFGENERIC), the compiler will
complain until you have changed it in all the other places.  There's no
chance of anything ever getting out of sync like there is with some kinds
of duplication (which is why I tend not to like duplication in general).

Thanks again to everyone who replied.

Cheers,
	Bill.
-- 
"If you give someone Fortran, he has Fortran. If you give someone Lisp,
he has any language he pleases." -- Guy Steele
From: Peter Seibel
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <m3wtwywuhh.fsf@javamonkey.com>
William Bland <·······@abstractnonsense.com> writes:

> On Sat, 06 Nov 2004 11:07:31 +0000, Tim Bradshaw wrote:
>
>> * Brian Downing wrote:
>> 
>>> The most "non-kludgey" way I can think of is to use the PROGN method
>>> combination.  That spells out clearly what you're trying to accomplish.
>> 
>>> Unfortunatly, it runs most-specific-first:
>> 
>> Not necessarily!
>> 
>> (defgeneric foo (x)
>>   (:method-combination progn :most-specific-last))
>> 
>
> Cool!  Thanks very much to all who replied.
>
> I'm still not sure about one thing though:
>
> If the DEFGENERIC, we say that we want the method combination for
> this generic function to be PROGN. Why do we have to then
> effectively repeat this information in each DEFMETHOD?
>
> I had a quick look at the HyperSpec section on
> DEFINE-METHOD-COMBINATION, and it looked to me like this duplication
> of information could have been avoided if the PROGN method
> combination was defined using the long form of
> DEFINE-METHOD-COMBINATION. Presumably there's a good reason not to
> do it that way?

Well one advantage is that when you're looking at an individual method
you know that it's going to be combined with other methods in a
particular way. I think that's probably a good idea, particularly when
the GF is defined in one place and the methods elsewhere.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Pascal Costanza
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <cmh886$dda$1@newsreader2.netcologne.de>
William Bland wrote:
> I'm still to new to CLOS to know if this is the Right Thing, or just an
> ugly hack.
> 
> I was thinking of ways of making class hierarchies and defining methods on
> them, in the case where you *always* want to call the method that
> specialises on the superclass as well as the one that specialises on the
> class at hand.  You could use CALL-NEXT-METHOD, but then you have to
> remember to do it every time you define a new subclass and a method
> specialising on it.
> 
> The solution (hack?) I came up with was:
> 
> (defclass shape ()
>   ((mass :initform 0 :initarg :mass)))
> 
> (defclass circle (shape)
>   ((x :initform 0 :initarg :x)
>    (y :initform 0 :initarg :x)
>    (radius :initform 0 :initarg :radius)))
> 
> (defclass square (shape)
>   ((x :initform 0 :initarg :x)
>    (y :initform 0 :initarg :y)
>    (width :initform 0 :initarg :width)))
> 
> (defgeneric check (arg))
> 
> (defmethod check :before ((arg shape))
>   ; everything that inherits from shape needs its mass checking
>   (assert (> (slot-value arg 'mass) 0)))
> 
> (defmethod check ((arg shape))
>   nil) ; nothing else to check
> 
> (defmethod check ((arg circle))
>   (assert (> (slot-value arg 'radius) 0)))
> 
> (defmethod check ((arg square))
>   (assert (> (slot-value arg 'width) 0)))
> 
> So is that a normal thing to do?  Is there any reason why it's not good
> form?  Is there a much better way that I've completely overlooked?

"Much better" is probably exaggerated, but you seem to want a progn 
method combination:

(defgeneric check (arg)
   (:method-combination progn))

(defmethod check progn ((arg shape))
   (assert (> (slot-value arg 'mass) 0)))

(defmethod check progn ((arg circle))
   (assert (> (slot-value arg 'radius) 0))

etc.

...or maybe an and method combination:

(defgeneric check (arg)
   (:method-combination and))

(defmethod check :around (arg)
   (assert (call-next-method)))

(defmethod check and (arg)
   (> (slot-value arg 'mass) 0))

(defmethod check and (arg)
   (> (slot-value arg 'radius) 0))

etc.


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Kenny Tilton
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <FDWid.117833$Ot3.78736@twister.nyc.rr.com>
William Bland wrote:
> I'm still to new to CLOS to know if this is the Right Thing, or just an
> ugly hack.
> 
> I was thinking of ways of making class hierarchies and defining methods on
> them, in the case where you *always* want to call the method that
> specialises on the superclass as well as the one that specialises on the
> class at hand.  You could use CALL-NEXT-METHOD, but then you have to
> remember to do it every time you define a new subclass and a method
> specialising on it.
> 
> The solution (hack?) I came up with was:
> 
> (defclass shape ()
>   ((mass :initform 0 :initarg :mass)))
> 
> (defclass circle (shape)
>   ((x :initform 0 :initarg :x)
>    (y :initform 0 :initarg :x)
>    (radius :initform 0 :initarg :radius)))
> 
> (defclass square (shape)
>   ((x :initform 0 :initarg :x)
>    (y :initform 0 :initarg :y)
>    (width :initform 0 :initarg :width)))
> 
> (defgeneric check (arg))
> 
> (defmethod check :before ((arg shape))
>   ; everything that inherits from shape needs its mass checking
>   (assert (> (slot-value arg 'mass) 0)))
> 
> (defmethod check ((arg shape))
>   nil) ; nothing else to check
> 
> (defmethod check ((arg circle))
>   (assert (> (slot-value arg 'radius) 0)))
> 
> (defmethod check ((arg square))
>   (assert (> (slot-value arg 'width) 0)))
> 
> So is that a normal thing to do?  Is there any reason why it's not good
> form?  Is there a much better way that I've completely overlooked?
> 
> The reason I was thinking about this is that I really wanted to do the
> same thing in one of our Java programs at work, but I can see no way to
> achieve the same thing in Java.  I'll just have to tell everyone "remember
> to call super.foo() whenever you subclass and override foo".

While the progn others have suggested has some merit, i think it is a 
mistake in that one is then surrendering the flexibility of :around, 
:before, :after. You might end up with a bizarre shape which really does 
need to override anything in its superclass ancestry, in which case an 
around method lets you avoid running any other method. Or you might want 
some check to run :after because there is no point in making it if some 
other check has failed, and you do not want to be fooled each time by 
the false indicator of the dependent check going off first. No such fine 
tuning is possible once you enslave yourself to progn's ordering.

I would create an unspecialized primary method which does nothing, then 
express validation as before, after or around. This way no harm is done 
if someone accidentally code a primary method (unless someone else did, 
too <g>).

kenny

-- 
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
From: Peter Seibel
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <m31xf7y0mh.fsf@javamonkey.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> While the progn others have suggested has some merit, i think it is
> a mistake in that one is then surrendering the flexibility of
> :around, :before, :after. You might end up with a bizarre shape
> which really does need to override anything in its superclass
> ancestry, in which case an around method lets you avoid running any
> other method.

So if you need an :around method, use it. All the built-in method
combinations, such as PROGN, support :around methods.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kenneth Tilton
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <ktilton-3C6C39.12180606112004@nyctyp01-ge0.rdc-nyc.rr.com>
In article <··············@javamonkey.com>,
 Peter Seibel <·····@javamonkey.com> wrote:

> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> > While the progn others have suggested has some merit, i think it is
> > a mistake in that one is then surrendering the flexibility of
> > :around, :before, :after. You might end up with a bizarre shape
> > which really does need to override anything in its superclass
> > ancestry, in which case an around method lets you avoid running any
> > other method.
> 
> So if you need an :around method, use it. All the built-in method
> combinations, such as PROGN, support :around methods.

Oops. I never got past the bit in the error message about "all methods 
must be all XXXX or ...." <g>

But my point still stands: progn is cute, but it is the wrong hammer, 
because it runs from most specific to least. In validation, base checks 
should run before more specific checks. Why worry if the sides of a 
right triangle satisfy the Pythagorean Theorem if they cannot be a 
triangle (one is greater than the sum of the other two)? If the code is 
failing at creating even a triangle, you do not want the misleading 
error "sum of hypotenuse aint sum of squares of other sides".

btw, i am speaking from long experience with gui geometry and much 
wasted time tracking down false leads.

Doing something such as:

(defmethod chk :around ((this kind))
   (call-next-method)
   <specific checks for kind>)

...all the time is just another way of saying progn is the wrong tool.

kt
From: Kaz Kylheku
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <cf333042.0411060759.29c3ae8@posting.google.com>
William Bland <·······@abstractnonsense.com> wrote in message news:<······························@abstractnonsense.com>...
> I'm still to new to CLOS to know if this is the Right Thing, or just an
> ugly hack.

grasshopper

when thing make feel you arrogant and superior bashing java and c++
programmer in usenet with courage you know it is right thing with
capital r and capital t

until moment it is not right thing

keep search think working hard
From: Alan Crowe
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <86lldcrxd9.fsf@cawtech.freeserve.co.uk>
William Bland studied CLOS and asked:
> I was thinking of ways of making class hierarchies and
> defining methods on them, in the case where you *always*
> want to call the method that specialises on the superclass
> as well as the one that specialises on the class at hand.

I feel strangely drawn to define-method-combination. Perhaps
I feel patronised by Keene. I resented reading a whole book
on CLOS only to find that I hadn't even covered everything
in the standard, let along any of the meta-object protocol.

;;; VALIDATE method combination

;;; Runs all the :validate methods, from least specific to most specific,
;;; discarding their values.
;;; Then runs most specific unqualified message, returning its values.

;;; Order rationale. We assume that the tests for validity
;;; are built up sucessively with the test for each class
;;; assuming that the super classes are valid,

(defun wrapcar (func item-list)
  (mapcar (lambda (item) (list func item))
	  item-list))

(define-method-combination validate ()
  ((act nil)
   (check (:validate) :order :most-specific-last))
  `(progn ,@(wrapcar 'call-method check)
	  (call-method ,(car act))))

;;; Examples

(defclass heavy ()
  ((weight :accessor weight :initarg :weight)))

(defclass hot ()
  ((temperature :accessor temperature :initarg :temperature)))

(defgeneric assess (x)
  (:method-combination validate))

(defmethod assess :validate ((x heavy))
  (print "checking weight"))

(defmethod assess :validate ((x hot))
  (print "checking temperature"))

(defmethod assess (x)
  (print "It is valid.")
  (quote valid))

(defclass lump (hot heavy)())

(assess (make-instance 'lump :weight 70 :temperature 300))
=>
"checking weight" 
"checking temperature" 
"It is valid." 
VALID

(defclass dollop (heavy hot)())

(assess (make-instance 'dollop :weight 70 :temperature 300))
=>
"checking temperature" 
"checking weight" 
"It is valid." 
VALID

Notice that a :validate method differs from a :before method
in running most specific last, and differs from an :after
method in running before the primary method.

I like the feeling of being able to tune method combination.
Here is a variant on the above

;;; GUARD method combination
;;; Runs :guard methods, signalling an error immediately one
;;; of them rejects the object by not returning nil.
;;; If they all pass, run most specific primary method
(define-method-combination test ()
  ((action nil)
   (guards (:guard) :order :most-specific-last))
  `(let ((alarm (or ,@(wrapcar 'call-method guards))))
     (if alarm 
	 (error "Guard rejects object because it is ~A." alarm)
       (call-method ,(car action)))))

(defgeneric cooking-time (x)
  (:method-combination test))

(defmethod cooking-time :guard ((thing heavy))
  (if (< (weight thing) 50) 'too-light))

(defmethod cooking-time :guard ((thing hot))
  (if (< (temperature thing) 300) 'not-hot-enough))

(defmethod cooking-time ((meat lump))
  (float (* 60
	    (/ (+ (weight meat) 30)
	       (- (temperature meat) 200)))))

CL-USER(64): (cooking-time (make-instance 'lump :weight 100 :temperature 400))
39.0
CL-USER(65): (cooking-time (make-instance 'lump :weight 100 :temperature 200))
Error: Guard rejects object because it is NOT-HOT-ENOUGH.

I think there is the germ of something important here.
Look at OOP from the point of view of code reuse. If the
most specific method runs /instead/ of the less specific
methods, then the code specialised on the superclasses is
not getting reused. Ideally the most specific method
contains relatively little code, but uses call-next-method
to run, and thus reuse, code from less specific methods.

One is trying to design the methods and the class hierarchy
so that one reuses all the common code. Perhaps it goes more
smoothly if one has an extra degree of freedom and tries to
design the methods, the class hierarchy, and the method
combination to maximise the reuse of common code.

However, I'm still new to CLOS myself. I've few clues as to
whether or not this works out in practise. One migh even
fret that this post is a case of the blind leading the bland
:-)

Alan Crowe
Edinburgh
Scotland
From: William Bland
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <pan.2004.11.08.23.17.38.159222@abstractnonsense.com>
On Mon, 08 Nov 2004 18:47:46 +0000, Alan Crowe wrote:

> However, I'm still new to CLOS myself. I've few clues as to
> whether or not this works out in practise.

Well it all looked very interesting to me.  I need to think about this
stuff more though... there's certainly a huge potential amount of power in
being able to redefine method combinations.

> One migh even
> fret that this post is a case of the blind leading the bland

ROTFL :-)

Cheers,
	Bill.
-- 
"If you give someone Fortran, he has Fortran. If you give someone Lisp,
he has any language he pleases." -- Guy Steele
From: Tim Bradshaw
Subject: Re: Is this the Right Thing?
Date: 
Message-ID: <ey3zn1rzcla.fsf@cley.com>
* Alan Crowe wrote:
> One is trying to design the methods and the class hierarchy
> so that one reuses all the common code. Perhaps it goes more
> smoothly if one has an extra degree of freedom and tries to
> design the methods, the class hierarchy, and the method
> combination to maximise the reuse of common code.

> However, I'm still new to CLOS myself. I've few clues as to
> whether or not this works out in practise. One migh even
> fret that this post is a case of the blind leading the bland
> :-)

When I implemented the WRAPPING-STANDARD method combination (which
just adds least-specific-outermost wrapping methods, which I used for
argument defaulting in GFs) for an application I was working on, I
found that over the next few days I reimplemented a substantial amount
of code to use it, and also got rid of a bunch of `don't define around
methods for this, or if you do make sure you do all the hairy argument
defaulting' comments.

So I think method combinations can be a win.