From: Joel Reymont
Subject: Multiple inheritance
Date: 
Message-ID: <1148909884.509850.164310@38g2000cwa.googlegroups.com>
(in-package :cl-user)

(defclass x () ())
(defclass y () ())

(defmethod foo ((self x)) (format t "foo-x~%"))
(defmethod foo ((self y)) (format t "foo-y~%"))

(defclass z (x y) ())
(defmethod foo :after ((self z)) (format t "foo-z~%"))

(foo (make-instance 'z))
foo-x
foo-z

I was expecting y's foo to be called as well but  it wasn't.

Is this effect described somewhere?

    Thanks, Joel

From: Christophe Rhodes
Subject: Re: Multiple inheritance
Date: 
Message-ID: <sqslms29x7.fsf@cam.ac.uk>
"Joel Reymont" <······@gmail.com> writes:

> I was expecting y's foo to be called as well but it wasn't.

Well, no.  Why were you expecting "y's foo" (you mean "the primary
method of foo specialized on Y") to be called?

> Is this effect described somewhere?

Determining the effective method of a generic function call is
described in the CL standard, section 7.6.6.1.  Standard method
combination is described in the CL standard, section 7.6.6.2.

Christophe
From: Luís Oliveira
Subject: Re: Multiple inheritance
Date: 
Message-ID: <m2u078zyr5.fsf@deadspam.com>
"Joel Reymont" <······@gmail.com> writes:
> (defmethod foo ((self x)) (format t "foo-x~%"))
> (defmethod foo ((self y)) (format t "foo-y~%"))
[...]
> (defclass z (x y) ())
[...]
> I was expecting y's foo to be called as well but  it wasn't.
>
> Is this effect described somewhere?

See:
http://gigamonkeys.com/book/object-reorientation-generic-functions.html

Namely, check out CALL-NEXT-METHOD and the PROGN method combination.

-- 
Luís Oliveira
luismbo (@) gmail (.) com
http://student.dei.uc.pt/~lmoliv/
From: Pascal Bourguignon
Subject: Re: Multiple inheritance
Date: 
Message-ID: <87irno29g8.fsf@thalassa.informatimago.com>
"Joel Reymont" <······@gmail.com> writes:

> (in-package :cl-user)
>
> (defclass x () ())
> (defclass y () ())
>
> (defmethod foo ((self x)) (format t "foo-x~%"))
> (defmethod foo ((self y)) (format t "foo-y~%"))
>
> (defclass z (x y) ())
> (defmethod foo :after ((self z)) (format t "foo-z~%"))
>
> (foo (make-instance 'z))
> foo-x
> foo-z
>
> I was expecting y's foo to be called as well but  it wasn't.

You could try this:

(in-package :cl-user)

(defclass x () ())
(defclass y () ())

(defmethod foo ((self x)) (format t "foo-x~%") (ignore-errors(call-next-method)))
(defmethod foo ((self y)) (format t "foo-y~%") (ignore-errors(call-next-method)))

(defclass z (x y) ())
(defmethod foo :after ((self z)) (format t "foo-z~%"))

(foo (make-instance 'z))

Prints:
foo-x
foo-y
foo-z

Returns:
--> NIL ;
    #<METHOD-CALL-ERROR #x20550B66>

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay
From: Ken Tilton
Subject: Re: Multiple inheritance
Date: 
Message-ID: <qaMeg.62$XB5.2@fe09.lga>
Joel Reymont wrote:
> (in-package :cl-user)
> 
> (defclass x () ())
> (defclass y () ())
> 
> (defmethod foo ((self x)) (format t "foo-x~%"))
> (defmethod foo ((self y)) (format t "foo-y~%"))
> 
> (defclass z (x y) ())
> (defmethod foo :after ((self z)) (format t "foo-z~%"))
> 
> (foo (make-instance 'z))
> foo-x
> foo-z
> 
> I was expecting y's foo to be called as well but  it wasn't.
> 
> Is this effect described somewhere?

Others have answered, but... the effect you were expecting is true of 
after methods and around methods (unless one starts mucking with 
call-next-method, but let's call that A Different Story).

If you had simply inherited from x in defining y... well, hang on, maybe 
you would not have expected both x and y primary methods called. Would 
you have? If not (and I suspect you did not offer a multiply-inherent 
example by accident), we have a deeper problem:

You might be visualizing x and y as somehow side-by-side, meaning both 
GFs should run. nahhh, try (class-precedence-list (find-class 'z)). x is 
higher, x runs.

kt

-- 
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
    Attorney for Mary Winkler, confessed killer of her
    minister husband, when asked if the couple had
    marital problems.
From: Joel Reymont
Subject: Re: Multiple inheritance
Date: 
Message-ID: <1148950869.022475.284080@g10g2000cwb.googlegroups.com>
This does the trick, kudos to Luis!

(in-package :cl-user)

(defclass x () ())
(defclass y () ())

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

(defmethod foo progn ((self x)) (format t "foo-x~%"))
(defmethod foo progn ((self y)) (format t "foo-y~%"))

(defclass z (y x) ())
(defmethod foo progn ((self z)) (format t "foo-z~%"))

(foo (make-instance 'z))
;; foo-x
;; foo-y
;; foo-z

Pascal's example is also interesting (thanks!), although it would be
cool to know exactly which call-next-method will signal an error and
just omit it.
From: Peter Seibel
Subject: Re: Multiple inheritance
Date: 
Message-ID: <m264jojnv0.fsf@gigamonkeys.com>
"Joel Reymont" <······@gmail.com> writes:

> This does the trick, kudos to Luis!
>
> (in-package :cl-user)
>
> (defclass x () ())
> (defclass y () ())
>
> (defgeneric foo (self)
>   (:method-combination progn :most-specific-last))
>
> (defmethod foo progn ((self x)) (format t "foo-x~%"))
> (defmethod foo progn ((self y)) (format t "foo-y~%"))
>
> (defclass z (y x) ())
> (defmethod foo progn ((self z)) (format t "foo-z~%"))
>
> (foo (make-instance 'z))
> ;; foo-x
> ;; foo-y
> ;; foo-z
>
> Pascal's example is also interesting (thanks!), although it would be
> cool to know exactly which call-next-method will signal an error and
> just omit it.

  (when (next-method-p) (call-next-method))

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Joel Reymont
Subject: Re: Multiple inheritance
Date: 
Message-ID: <1148978950.822130.176510@g10g2000cwb.googlegroups.com>
This works too

(in-package :cl-user)

(defclass x () ())
(defclass y () ())

(defmethod foo ((self x))
  (format t "foo-x~%")
  (call-next-method))

(defmethod foo ((self y))
  (format t "foo-y~%"))

(defclass z (x y) ())
(defmethod foo :after ((self z)) (format t "foo-z~%"))

(foo (make-instance 'z))
;; foo-x
;; foo-y
;; foo-z

It's intuitive to call-next-method for x but not completely intuitive
to have :after on z.

It's more intuitive to

(defmethod foo ((self z))
  (call-next-method)
  (format t "foo-z~%"))

Shame on me for I do have "The Art of the MOP" on my shelf.
From: Luís Oliveira
Subject: Re: Multiple inheritance
Date: 
Message-ID: <m2mzczss1j.fsf@deadspam.com>
"Joel Reymont" <······@gmail.com> writes:
> It's intuitive to call-next-method for x but not completely intuitive
> to have :after on z.
>
> It's more intuitive to
>
> (defmethod foo ((self z))
>   (call-next-method)
>   (format t "foo-z~%"))

It's not the same thing, though.

;; standard method combination
(defgeneric foo (object))

(defmethod foo :after ((self x))
  (write-line "after x"))

(defmethod foo :after ((self y))
  (write-line "after y"))

(defmethod foo :after ((self z))
  (write-line "after z"))

(defmethod foo ((self z))
  (write-line "main z"))


CL-USER> (foo (make-instance 'z))
main z
after y
after x
after z

If, say, the "after y" or "after x" methods were actually main methods
calling call-next-method, they wouldn't run at all.


> Shame on me for I do have "The Art of the MOP" on my shelf.

I haven't read it but from what I hear, Sonya Keene's _Object-Oriented
Programming in Common Lisp: A Programmer's Guide to CLOS_ is probably
more relevant.

PCL's "object reorientation" chapters about CLOS tackle this too.

-- 
Luís Oliveira
luismbo (@) gmail (.) com
http://student.dei.uc.pt/~lmoliv/