Hello, May I first please reduce your test case. Here is an equivalent version:
(use-modules (oop goops)) (define-class <a> () (foo #:getter foo #:init-keyword #:foo)) (define-class <b> (<a>)) (define obj (make <b> #:foo 34)) (define-method (foo (self <b>)) (pk "ahoy!") (next-method)) (pk (foo obj)) It has nothing to do with modules or setters, and everything to do with GOOPS and accessors. Anyway, this has been a confusing thread, so let me summarize: It used to be, in Guile 1.8, that the test case didn't work at all: n guile> (pk (foo obj)) ;;; ("ahoy!") Backtrace: In current input: 18: 0* [peek ... 18: 1* [foo #<<b> 7fc8898e0e20>] ?: 2 (let* ((next-method (goops:make-next-method self))) (pk "ahoy!") ...) <unnamed port>: In expression (let* (#) (pk "ahoy!") ...): <unnamed port>: No next method when calling #<<generic> foo (2)> with arguments (#<<b> 7fc8898e0e20>) It is important to note what the behavior was in Guile 1.8 because it is the version that is closest to what Mikael originally wrote (or inherited from stklos); though there are many ways in which GOOPS could be better, I have been surprised again and again about the thoroughness of the original implementation. In Guile 2.0, I made an error that accidentally made this test case "work", in the sense that it would return the value of the slot "foo". scheme@(guile-user)> (pk (foo obj)) ;;; ("ahoy!") ;;; (34) $1 = 34 However it wouldn't always return the value of the slot "foo"; for example: scheme@(guile-user)> (define-class <c> () (bar #:init-keyword #:bar)) scheme@(guile-user)> (define-class <ac> (<a> <c>)) scheme@(guile-user)> (define obj2 (make <ac> #:foo 34 #:bar 42)) scheme@(guile-user)> (define-method (foo (self <ac>)) (pk "wat!!!") (next-method)) scheme@(guile-user)> (pk (foo obj2)) ;;; ("wat!!!") ;;; (42) $2 = 42 Here you see that it returns the value of the "bar" slot. Why? Because defining the (foo (self <ac>)) method *replaced* the accessor method for `foo' on instances of type <ac> with our new method, and then the next-method that applies is the accessor method that is specialized on values of type <a>, which looks for the slot in field 0. I thought at first that this wasn't right, that really accessor methods need to specialize on the types that they actually see, not just their specializers; but that's not right, because not all subtypes of a type have all slots of all of their supertypes. That got me thinking and looking back, so I found the bug that I introduced. It turns out the GOOPS design is to add accessor methods for each subclass that has a given slot, and they are not designed to "inherit" -- i.e. an accessor method specialized on <base> shouldn't be in the next-method list for <derived>. I have recently made a change to restore us to Guile 1.8 behavior, so as to fix the "wat" bug above in Guile 2.0 and 2.2. > This said and with that in mind, the implementation you say was in guile-1.8 > and > that it appears you have reimplemented 'right now' breaks the specification > and > afaiac makes goops totally unusable for any serious work: this is a > catastrophy, > please reconsider! David, I would really appreciate it if you could tone down the hyperbole. Thanks in advance :) > When talking about goops, we should not refer to 1.8 (*), 1.6 or any guile > version > for that matter, but to the clos language spec subset goops implements > [appart from > the adaptation for it to be module protected, but that is not the point here]. (defclass <a> () ((foo :reader foo :initarg :foo))) (defclass <b> (<a>) ()) (defvar obj (make-instance '<b> :foo 34)) (defmethod foo ((self <b>)) (write "ahoy!") (call-next-method)) (foo obj) Interestingly, in CLISP at least this works in the way you expect: it prints "ahoy" and then chains up and returns the value. I also note that it doesn't install accessor methods on each subtype; before defining the "ahoy" method, I got this: > (generic-function-methods #'foo) (#<STANDARD-READER-METHOD (#<STANDARD-CLASS <A>>)>) And that method worked on instances of <b> just as well. I am not sure how to interpret this result. The slot definition protocol in CLOS is different; for example, compute-effective-slot-definition in CLOS logically *combines* slot definitions with the same name. Could it be that in CLOS, all instances of a type are considered to have all slots of all supertypes? That is not the GOOPS design, but perhaps that should change. Andy -- http://wingolog.org/