unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
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 --]

      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).