From: Tobias Brandt <tob.brandt@gmail.com>
To: Daniel Hartwig <mandyke@gmail.com>
Cc: "guile-user@gnu.org" <guile-user@gnu.org>
Subject: Re: GOOPS: calling next-method with different arguments.
Date: Mon, 22 Apr 2013 08:42:57 +0200 [thread overview]
Message-ID: <CAOOWqir6AG4kUsQCZ2aEX8L-k4j7AQHd5ZoYSesvQcj=zT8mtA@mail.gmail.com> (raw)
In-Reply-To: <CAN3veRf=Re4Kh=r6McWt5Km9SOfGOY0+0dz=B6uWidHnp6K-UA@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 5668 bytes --]
> When changing the _type_ of an argument this will perhaps not have the
> desired result. You have to consider the specific situation quite
> careful.
I'm aware of that. The CL hyperspec comes with the same warning.
I would probably only use it for initialize, where the next method
is basically the super class constructor.
> I have to wonder, what is the purpose of your real <bar> anyway? Is
> it just a convenience so you can construct the base class using a
> number instead of a string?
There is no real <bar>, it was just a stupid example. I was hoping to do
some
OOP in Scheme in the future and thought about how things translate from
Java/C#.
I know, it's not always a could idea to just literally translate things
from one
language to another.
Cheers,
Tobias
On 22 April 2013 06:39, Daniel Hartwig <mandyke@gmail.com> wrote:
> On 22 April 2013 01:17, Tobias Brandt <tob.brandt@gmail.com> wrote:
> > I just noticed something: next-method *already* supports calling it with
> > different arguments. It's just not documented.
> >
>
> When changing the _type_ of an argument this will perhaps not have the
> desired result. You have to consider the specific situation quite
> careful.
>
> The list of applicable methods is already computed before
> ‘next-method’ is invoked, and is based on the argument types in the
> original call. If you change any of these types the applicable
> methods are not recomputed, and neither should they be. The entire
> applicable list and call tree will potentially be quite different. So
> this will only work when the _already computed_ next method is
> compatible with the new argument types, but even then, the method you
> arrive at may be less specialized than is desired (i.e. dispatching on
> <object> rather than <string>).
>
> In your actual use case involving object construction, you can
> specialize ‘initialize’ (see later) and ‘next-method’ will work fine
> because ‘initialize’ is not dispatching on argument types other than
> the class. The next method is the next superclass' intializer in most
> situations, which is what you want.
>
> Generally however, and in cases like the example you gave for ‘f’, it
> will not work to change argument types with ‘next-method’. Suppose
> you want a method specialized on the base class and a string:
>
> (define-method (g (foo <foo>) (x <string>))
> (format #t "foo: ~a\n" x))
>
> and another method specialized on the derived class and a number:
>
> (define-method (g (bar <bar>) (x <number>))
> (next-method self (number->string x))
> (format #t "bar: ~a\n" x))
>
> When you make the original call, the list of applicable methods is:
>
> (compute-applicable-methods g (list (make <bar>) 1))
> => (#<<method> (<bar> <number>) 99840a0>)
>
> Note that the method dispatching on <foo> is not in that list, indeed
> there is only a single applicable method. Hence, the call to
> ‘next-method’ within the second method will throw an error:
>
> (g (make <bar>) 1)
> ERROR: In procedure scm-error:
> ERROR: No next method when calling #<<generic> g (2)>
> with arguments (#<<bar> 95d2138> "1")
>
> In a situation like this, just call the desired generic directly:
>
> (define-method (g (bar <bar>) (x <number>))
> (g bar (number->string x))
> (format #t "bar: ~a\n" x))
>
> which will be dispatched correctly considering the new type. This is
> effectively what you have done with ‘make’ in your previous post. The
> key point to take away is that when the argument type has been
> significant in dispatching the call, it is probably not correct to use
> ‘next-method’.
>
> > On 21 April 2013 18:05, Tobias Brandt <tob.brandt@gmail.com> wrote:
> >>
> >> Hi,
> >>
> >> thanks for your input. I tried to avoid the whole next-method issue
> >> entirely and defined a method for make on bar's metaclass instead.
> >>
> >> (use-modules (oop goops))
> >>
> >> (define-class <foo> () (s #:init-keyword #:s))
> >> (define-class <bar-class> (<class>))
> >> (define-class <bar> (<foo>) #:metaclass <bar-class>)
> >>
> >> (define-method (make (self <bar-class>) (i <integer>))
> >> (make self #:s (number->string i)))
> >>
>
> I would actually call that argument ‘class’ rather than ‘self’.
>
> Specializing ‘make’ like this is perhaps inconvenient for classes
> derived from <bar>, or when there are more slots to initialize with
> keywords. It does not take any rest argument, and the integer
> argument omits a keyword that is otherwise typical of ‘make’ and
> ‘initialize’ methods. Instead, you can specialize ‘initialize’ and
> avoid using a custom metaclass and atypical ‘make’:
>
> ;; Using a unique keyword #:i for <bar>:
> (use-modules (ice-9 optargs))
> (define-method (initialize (bar <bar>) initargs)
> (let-keywords initargs #t
> (i)
> (cond (i (next-method bar (append `(#:s ,(number->string i))
> initargs)))
> (else (next-method)))))
>
>
> I have to wonder, what is the purpose of your real <bar> anyway? Is
> it just a convenience so you can construct the base class using a
> number instead of a string? If so, why not just use:
>
> (define-method (make-bar (i <integer>))
> (make <foo> #:s (number->string i)))
>
> >> However, I have no idea what the performance implications of creating a
> >> new metaclass are. IIRC, in Smalltalk every class has its own metaclass
> >> automatically and that doesn't seem to cause any problems.
> >>
>
> Likewise in GOOPS, all objects use a metaclass (usually <class> in
> typical cases).
>
[-- Attachment #2: Type: text/html, Size: 8064 bytes --]
prev parent reply other threads:[~2013-04-22 6:42 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-19 7:18 GOOPS: calling next-method with different arguments Tobias Brandt
2013-04-19 8:54 ` Panicz Maciej Godek
2013-04-19 22:58 ` Panicz Maciej Godek
2013-04-21 16:05 ` Tobias Brandt
2013-04-21 17:17 ` Tobias Brandt
2013-04-22 4:39 ` Daniel Hartwig
2013-04-22 6:42 ` Tobias Brandt [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAOOWqir6AG4kUsQCZ2aEX8L-k4j7AQHd5ZoYSesvQcj=zT8mtA@mail.gmail.com' \
--to=tob.brandt@gmail.com \
--cc=guile-user@gnu.org \
--cc=mandyke@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).