unofficial mirror of bug-guile@gnu.org 
 help / color / mirror / Atom feed
* bug#37461: define-generic doesn't promote equal? to generic
@ 2019-09-19 15:37 Rob Browning
  2019-09-19 23:27 ` Rob Browning
  0 siblings, 1 reply; 7+ messages in thread
From: Rob Browning @ 2019-09-19 15:37 UTC (permalink / raw)
  To: 37461


Version: 2.2.6

  scheme@(guile-user)> (use-modules (oop goops))
  scheme@(guile-user)> equal?
  $1 = #<procedure equal? (#:optional _ _ . _)>
  scheme@(guile-user)> (define-generic equal?)
  scheme@(guile-user)> equal?
  $2 = #<procedure equal? (#:optional _ _ . _)>

The same appears to be true for other primitives like + too, but if I'm
reading it right, this makes it sound like it was intended to work:

  https://www.gnu.org/software/guile/docs/master/guile.html/Extending-Primitives.html

You can work around the problem by stashing equal? somewhere else, and
then define-generic will work after a (define equal? #f).  Presumably
you'd then need to define a base specialization using the original
equal? or do something equivalent.

I also noticed goops itself does this: https://git.savannah.gnu.org/gitweb/?p=guile.git;a=blob;f=module/oop/goops.scm;h=837a667e602\
5b6f8ed7818e5a8efe064cca7843d;hb=791cae940afcb2b2eb2c167fe438be1dc1008a73#l2335

Thanks
-- 
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#37461: define-generic doesn't promote equal? to generic
  2019-09-19 15:37 bug#37461: define-generic doesn't promote equal? to generic Rob Browning
@ 2019-09-19 23:27 ` Rob Browning
  2019-09-21 15:15   ` Rob Browning
  2019-09-21 17:08   ` Rob Browning
  0 siblings, 2 replies; 7+ messages in thread
From: Rob Browning @ 2019-09-19 23:27 UTC (permalink / raw)
  To: 37461

Rob Browning <rlb@defaultvalue.org> writes:

> You can work around the problem by stashing equal? somewhere else, and
> then define-generic will work after a (define equal? #f).  Presumably
> you'd then need to define a base specialization using the original
> equal? or do something equivalent.

It looks like while this works within a module, I haven't figured out
any workaround that allows the module to present the resulting generic
equal? to code that uses the module.

A re-export doesn't affect the module using the re-exporter, and export
and replace both fail with "Unbound variable: equal?", even though
there's a (define equal?  ...)  in the module.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#37461: define-generic doesn't promote equal? to generic
  2019-09-19 23:27 ` Rob Browning
@ 2019-09-21 15:15   ` Rob Browning
  2019-09-21 17:08   ` Rob Browning
  1 sibling, 0 replies; 7+ messages in thread
From: Rob Browning @ 2019-09-21 15:15 UTC (permalink / raw)
  To: 37461; +Cc: control

retitle 37461 Methods added to primitive generics don't always work
thanks

Rob Browning <rlb@defaultvalue.org> writes:

> A re-export doesn't affect the module using the re-exporter, and export
> and replace both fail with "Unbound variable: equal?", even though
> there's a (define equal?  ...)  in the module.

It looks like equal? isn't changed by define-generic, etc. because it
already has "generic-capability?".  And in fact, I can see that defining
a method on it does alter its primitive-generic-generic, but then
dispatch to the new method doesn't always seem to work (or perhaps I
just misunderstand the dispatch rules).

Here a one argument specialization doesn't work, but a two argument
specialization does -- for new classes, but not for a "standard" class
like <string>:

  scheme@(guile-user)> (use-modules (oop goops))
  scheme@(guile-user)> (primitive-generic-generic equal?)
  $1 = #<<generic> equal? (1)>

  scheme@(guile-user)> (define-class <foo> () (data))
  scheme@(guile-user)> (define-method (equal? (x <foo>)) 'x)
  scheme@(guile-user)> (primitive-generic-generic equal?)
  $2 = #<<generic> equal? (2)>
  scheme@(guile-user)> (equal? (make <foo>))
  $3 = #t

  scheme@(guile-user)> (define-method (equal? (x <foo>) (y <foo>)) 'x)
  $4 = #<<generic> equal? (3)>
  scheme@(guile-user)> (equal? (make <foo>) (make <foo>))
  $5 = x

  scheme@(guile-user)> (define-method (equal? (x <string>) (y <string>)) 'x)
  $6 = #<<generic> equal? (4)>
  scheme@(guile-user)> (equal? "x" "y")
  $7 = #f

Thanks
-- 
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#37461: define-generic doesn't promote equal? to generic
  2019-09-19 23:27 ` Rob Browning
  2019-09-21 15:15   ` Rob Browning
@ 2019-09-21 17:08   ` Rob Browning
  2019-09-23 15:01     ` Mikael Djurfeldt
  1 sibling, 1 reply; 7+ messages in thread
From: Rob Browning @ 2019-09-21 17:08 UTC (permalink / raw)
  To: 37461

Rob Browning <rlb@defaultvalue.org> writes:

> A re-export doesn't affect the module using the re-exporter, and export
> and replace both fail with "Unbound variable: equal?", even though
> there's a (define equal?  ...)  in the module.

Perhaps there was something else going on, but now :replace does appear
to work, e.g. if I define a completely new generic and then

  (define equal? new-equal)

a "replace: (equal?)" in the define-module does appear to work when you
use the module.

Though define-method still ignores attempts to specialize (or change the
specialization) for existing types like <string>, etc. (as mentioned in
my other message).

Thanks
-- 
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#37461: define-generic doesn't promote equal? to generic
  2019-09-21 17:08   ` Rob Browning
@ 2019-09-23 15:01     ` Mikael Djurfeldt
  2019-09-28 16:51       ` Mikael Djurfeldt
  0 siblings, 1 reply; 7+ messages in thread
From: Mikael Djurfeldt @ 2019-09-23 15:01 UTC (permalink / raw)
  To: Rob Browning; +Cc: 37461

[-- Attachment #1: Type: text/plain, Size: 1972 bytes --]

Hi Rob,

I left GOOPS development at Guile version 1.8. The way this was then
intended to work was that

  (define-generic equal?)

means that you want to create a new generic equal?. This discards the old
binding for equal?.

  (define-method (equal? (a <string>) (b <string>)) ...)

on the other hand, means that you want to *extend* the current behavior of
equal? with a specialization to two strings. The method is then added to
equal?, which in guile-1.8 was from scratch a "primitive-generic".

Here's the actual output of guile-1.8:

guile> equal?
#<primitive-generic equal?>
guile> (use-modules (oop goops))
guile> (define-method (equal? (a <string>) (b <string>)) (string=? a b))
guile> equal?
#<primitive-generic equal?>
guile> (primitive-generic-generic equal?)
#<<generic> equal? (2)>
guile> (define-generic equal?)
guile> equal?
#<<generic> equal? (0)>

I don't know if the changes between 1.8 and 2.2.6 is intentional or a bug.
Does someone here know?

Best regards,
Mikael

On Sat, Sep 21, 2019 at 7:09 PM Rob Browning <rlb@defaultvalue.org> wrote:

> Rob Browning <rlb@defaultvalue.org> writes:
>
> > A re-export doesn't affect the module using the re-exporter, and export
> > and replace both fail with "Unbound variable: equal?", even though
> > there's a (define equal?  ...)  in the module.
>
> Perhaps there was something else going on, but now :replace does appear
> to work, e.g. if I define a completely new generic and then
>
>   (define equal? new-equal)
>
> a "replace: (equal?)" in the define-module does appear to work when you
> use the module.
>
> Though define-method still ignores attempts to specialize (or change the
> specialization) for existing types like <string>, etc. (as mentioned in
> my other message).
>
> Thanks
> --
> Rob Browning
> rlb @defaultvalue.org and @debian.org
> GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
> GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4
>
>
>
>

[-- Attachment #2: Type: text/html, Size: 2963 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#37461: define-generic doesn't promote equal? to generic
  2019-09-23 15:01     ` Mikael Djurfeldt
@ 2019-09-28 16:51       ` Mikael Djurfeldt
  2019-09-28 17:31         ` Rob Browning
  0 siblings, 1 reply; 7+ messages in thread
From: Mikael Djurfeldt @ 2019-09-28 16:51 UTC (permalink / raw)
  To: Rob Browning; +Cc: 37461

[-- Attachment #1: Type: text/plain, Size: 1446 bytes --]

On Mon, Sep 23, 2019 at 5:01 PM Mikael Djurfeldt <mikael@djurfeldt.com>
wrote:

>
>   (define-method (equal? (a <string>) (b <string>)) ...)
>
> on the other hand, means that you want to *extend* the current behavior of
> equal? with a specialization to two strings. The method is then added to
> equal?, which in guile-1.8 was from scratch a "primitive-generic".
>
> Actually, this is misguided. I should have examined this problem more
carefully, and also read your later emails more carefully.

You see, I was under the impression that primitive-generic capability had
been removed for equal?. It has not. It's only the printed representation
which has changed.

Your bug report contains two problems. One concerns why define-generic
doesn't create a new generic. I believe this is an intentional or
unintentional change at some version. The other problem concerns the
dispatch rules for primitive generics.

You are right that the dispatch rules are special for primitive generics.
The purpose of primitive generics is to get around any performance penalty
for standard behavior, so primitive generics first try standard dispatch.
Then, if that fails, GOOPS method dispatch is used. The standard behavior
of equal? is to simply return #t when applied to a single argument
regardless of type. This is the explanation why you get #t for (equal?
<foo>).

One way to view this is that the dispatch of primitive-generics is
partially constrained.

[-- Attachment #2: Type: text/html, Size: 1919 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#37461: define-generic doesn't promote equal? to generic
  2019-09-28 16:51       ` Mikael Djurfeldt
@ 2019-09-28 17:31         ` Rob Browning
  0 siblings, 0 replies; 7+ messages in thread
From: Rob Browning @ 2019-09-28 17:31 UTC (permalink / raw)
  To: Mikael Djurfeldt; +Cc: 37461

Mikael Djurfeldt <mikael@djurfeldt.com> writes:

> You see, I was under the impression that primitive-generic capability had
> been removed for equal?. It has not. It's only the printed representation
> which has changed.

Ahh, right -- that confused me at first too.

> One way to view this is that the dispatch of primitive-generics is
> partially constrained.

Understood -- It'd be nice if the expectations were documented a bit
more clearly.  I'd be happy to propose something, assuming we can
determine what's appropriate, i.e. what Guile really intends to promise.

It sounds like:

  - This might need adjustment:

      8.6.2 Extending Primitives
      --------------------------

      Many of Guile's primitive procedures can be extended by giving them a
      generic function definition that operates in conjunction with their
      normal C-coded implementation.  When a primitive is extended in this
      way, it behaves like a generic function with the C-coded implementation
      as its default method.

    In particular, it sounds like the C-coded implementation actually
    takes precedence; it doesn't act like a normal default method.

    I suppose in practice, unless the behavior of the primitive-generic
    is very well specified, it might be best to avoid specializations
    for anything other than new types (that you're responsible for).
    Otherwise future changes might fairly mysteriously break things.

  - We're unsure whether define-generic is intended to do anything to a
    primitive generic, but if we can figure that out, I can adjust the
    define-generic documentation:

       -- syntax: define-generic symbol
           Create a generic function with name SYMBOL and bind it to the
           variable SYMBOL.  If SYMBOL was previously bound to a Scheme
           procedure (or procedure-with-setter), the old procedure (and
           setter) is incorporated into the new generic function as its
           default procedure (and setter).  Any other previous value,
           including an existing generic function, is discarded and replaced
           by a new, empty generic function.

    and might also mention the issue in the define-method docs.

Thanks
-- 
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4





^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-09-28 17:31 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-19 15:37 bug#37461: define-generic doesn't promote equal? to generic Rob Browning
2019-09-19 23:27 ` Rob Browning
2019-09-21 15:15   ` Rob Browning
2019-09-21 17:08   ` Rob Browning
2019-09-23 15:01     ` Mikael Djurfeldt
2019-09-28 16:51       ` Mikael Djurfeldt
2019-09-28 17:31         ` Rob Browning

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