unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* #:getter procedure returns unexpected value in GOOPS
@ 2014-04-25 23:24 Diogo F. S. Ramos
  2014-04-26 12:26 ` Neil Jerram
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Diogo F. S. Ramos @ 2014-04-25 23:24 UTC (permalink / raw)
  To: guile-user

When using GOOPS, if a class has a second slot, the #:getter procedure
of the first slot returns the value of the second slot when applied to
an instance of a subclass.

--8<---------------cut here---------------start------------->8---
(use-modules (oop goops))

(define-class <foo> ()
  (a #:init-form 'foo #:getter foo-a)
  (b #:init-form 42))

(define-class <bar> (<foo>)
  (a #:init-form 'bar))
--8<---------------cut here---------------end--------------->8---

  (foo-a (make <foo>)) => foo
  (foo-a (make <bar>)) => 42

I expected:

  (foo-a (make <bar>)) => bar

I'm not too familiar with GOOPS, so I'm not sure this is the right
behavior.

I'm using Guile 2.0.11.



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-25 23:24 #:getter procedure returns unexpected value in GOOPS Diogo F. S. Ramos
@ 2014-04-26 12:26 ` Neil Jerram
  2014-04-26 17:35   ` Diogo F. S. Ramos
  2014-04-27  1:15 ` Mark H Weaver
  2015-03-09 21:58 ` Andy Wingo
  2 siblings, 1 reply; 12+ messages in thread
From: Neil Jerram @ 2014-04-26 12:26 UTC (permalink / raw)
  To: Diogo F. S. Ramos; +Cc: guile-user

"Diogo F. S. Ramos" <dfsr@riseup.net> writes:

> When using GOOPS, if a class has a second slot, the #:getter procedure
> of the first slot returns the value of the second slot when applied to
> an instance of a subclass.
>
> (use-modules (oop goops))
>
> (define-class <foo> ()
>   (a #:init-form 'foo #:getter foo-a)
>   (b #:init-form 42))
>
> (define-class <bar> (<foo>)
>   (a #:init-form 'bar))
>
>   (foo-a (make <foo>)) => foo
>   (foo-a (make <bar>)) => 42
>
> I expected:
>
>   (foo-a (make <bar>)) => bar
>
> I'm not too familiar with GOOPS, so I'm not sure this is the right
> behavior.

Do you see this if you use #:init-value instead of #:init-form ?  It
sounds to me like #:init-value is what you really want, and I suspect
you're seeing undefined behaviour that arises from giving an
unparenthesized form ('42') to #:init-form.

     Neil



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-26 12:26 ` Neil Jerram
@ 2014-04-26 17:35   ` Diogo F. S. Ramos
  2014-04-26 22:19     ` David Pirotte
  0 siblings, 1 reply; 12+ messages in thread
From: Diogo F. S. Ramos @ 2014-04-26 17:35 UTC (permalink / raw)
  To: Neil Jerram; +Cc: guile-user

> "Diogo F. S. Ramos" <dfsr@riseup.net> writes:
>
>> When using GOOPS, if a class has a second slot, the #:getter procedure
>> of the first slot returns the value of the second slot when applied to
>> an instance of a subclass.
>>
>> (use-modules (oop goops))
>>
>> (define-class <foo> ()
>>   (a #:init-form 'foo #:getter foo-a)
>>   (b #:init-form 42))
>>
>> (define-class <bar> (<foo>)
>>   (a #:init-form 'bar))
>>
>>   (foo-a (make <foo>)) => foo
>>   (foo-a (make <bar>)) => 42
>>
>> I expected:
>>
>>   (foo-a (make <bar>)) => bar
>>
>> I'm not too familiar with GOOPS, so I'm not sure this is the right
>> behavior.
>
> Do you see this if you use #:init-value instead of #:init-form ?  It
> sounds to me like #:init-value is what you really want, and I suspect
> you're seeing undefined behaviour that arises from giving an
> unparenthesized form ('42') to #:init-form.

I tried changing all to `#:init-value', but the result was the same.

--8<---------------cut here---------------start------------->8---
(use-modules (oop goops))

(define-class <foo> ()
  (a #:init-value 'foo #:getter foo-a)
  (b #:init-value 42))

(define-class <bar> (<foo>)
  (a #:init-value 'bar))

(format #t "~a~%" (foo-a (make <foo>)))
(format #t "~a~%" (foo-a (make <bar>)))
--8<---------------cut here---------------end--------------->8---

Also, according to the documentation, it would not be what I want.

  INIT-VALUE specifies a fixed initial slot value (shared across all new
  instances of the class).

I want a slot value that is exclusive to an instance.

  INIT-FORM specifies a form that, when evaluated, will return an
  initial value for the slot.  The form is evaluated each time that an
  instance of the class is created, in the lexical environment of the
  containing ‘define-class’ expression.



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-26 17:35   ` Diogo F. S. Ramos
@ 2014-04-26 22:19     ` David Pirotte
  2014-04-26 22:58       ` Diogo F. S. Ramos
  0 siblings, 1 reply; 12+ messages in thread
From: David Pirotte @ 2014-04-26 22:19 UTC (permalink / raw)
  To: Diogo F. S. Ramos; +Cc: guile-user

Hello,

> I tried changing all to `#:init-value', but the result was the same.

Imo, using your definitions, guile should return 'foo, not 42.

But note that you do not define a getter in <bar>.  Still using your code the
following will work:

	(foo-a (make <foo>))
	(slot-ref (make <bar>) 'a)

Then if you define a getter..., you also get the expected result

Cheers,
David

;;

	GNU Guile 2.0.11.2-0ece4

	scheme@(guile-user)> 
	scheme@(guile-user)> 
	(use-modules (oop goops))

	(define-class <foo> ()
	  (a #:init-value 'foo #:getter foo-a)
	  (b #:init-value 42))

	(define-class <bar> (<foo>)
	  (a #:init-value 'bar #:getter foo-a))

	(foo-a (make <foo>))
	(foo-a (make <bar>))

	$2 = foo
	$3 = bar
	scheme@(guile-user)> 



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-26 22:19     ` David Pirotte
@ 2014-04-26 22:58       ` Diogo F. S. Ramos
  2014-04-27 22:14         ` David Pirotte
  0 siblings, 1 reply; 12+ messages in thread
From: Diogo F. S. Ramos @ 2014-04-26 22:58 UTC (permalink / raw)
  To: David Pirotte; +Cc: guile-user

>> I tried changing all to `#:init-value', but the result was the same.
>
> Imo, using your definitions, guile should return 'foo, not 42.

IMO it should return 'bar, as `foo-a' should return the value of the
slot `a', which in the subclass <bar> of <foo> is 'bar.



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-25 23:24 #:getter procedure returns unexpected value in GOOPS Diogo F. S. Ramos
  2014-04-26 12:26 ` Neil Jerram
@ 2014-04-27  1:15 ` Mark H Weaver
  2014-04-27 22:14   ` David Pirotte
  2015-03-09 21:58 ` Andy Wingo
  2 siblings, 1 reply; 12+ messages in thread
From: Mark H Weaver @ 2014-04-27  1:15 UTC (permalink / raw)
  To: Diogo F. S. Ramos; +Cc: guile-user

"Diogo F. S. Ramos" <dfsr@riseup.net> writes:

> When using GOOPS, if a class has a second slot, the #:getter procedure
> of the first slot returns the value of the second slot when applied to
> an instance of a subclass.
>
> (use-modules (oop goops))
>
> (define-class <foo> ()
>   (a #:init-form 'foo #:getter foo-a)
>   (b #:init-form 42))
>
> (define-class <bar> (<foo>)
>   (a #:init-form 'bar))
>
>   (foo-a (make <foo>)) => foo
>   (foo-a (make <bar>)) => 42
>
> I expected:
>
>   (foo-a (make <bar>)) => bar

Indeed, CLOS behaves as you expected, and GOOPS should probably behave
the same way.  However, it appears that overriding the attributes of
slots in subclasses has not worked this way in a long time, if ever.

I tried this example on both Guile 1.8 and Guile 1.6, and neither of
them behave as you expected.  Instead they complain that there's no
applicable method for 'foo-a'.

Can you please send a bug report to bug-guile@gnu.org?

For now, I suggest adding an initialize method for <bar>, like this:

--8<---------------cut here---------------start------------->8---
(use-modules (oop goops))

(define-class <foo> ()
  (a #:init-form 'foo #:getter foo-a)
  (b #:init-form 42))

(define-class <bar> (<foo>))

(define-method (initialize (obj <bar>) args)
  (slot-set! obj 'a 'bar)
  (next-method))

(foo-a (make <foo>)) => foo
(foo-a (make <bar>)) => bar
--8<---------------cut here---------------end--------------->8---

     Regards,
       Mark



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-26 22:58       ` Diogo F. S. Ramos
@ 2014-04-27 22:14         ` David Pirotte
  0 siblings, 0 replies; 12+ messages in thread
From: David Pirotte @ 2014-04-27 22:14 UTC (permalink / raw)
  To: Diogo F. S. Ramos; +Cc: guile-user

Hello Diego,

> > Imo, using your definitions, guile should return 'foo, not 42.

> IMO it should return 'bar, as `foo-a' should return the value of the
> slot `a', which in the subclass <bar> of <foo> is 'bar.

I am sorry, I ment no-applicable-method, I'll answer Mark's answer to explain why.

David



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-27  1:15 ` Mark H Weaver
@ 2014-04-27 22:14   ` David Pirotte
  2014-04-28  1:12     ` Mark H Weaver
  0 siblings, 1 reply; 12+ messages in thread
From: David Pirotte @ 2014-04-27 22:14 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-user

Hi Mark,

> > When using GOOPS, if a class has a second slot, the #:getter procedure
> > of the first slot returns the value of the second slot when applied to
> > an instance of a subclass.
> >
> > (use-modules (oop goops))
> >
> > (define-class <foo> ()
> >   (a #:init-form 'foo #:getter foo-a)
> >   (b #:init-form 42))
> >
> > (define-class <bar> (<foo>)
> >   (a #:init-form 'bar))
> >
> >   (foo-a (make <foo>)) => foo
> >   (foo-a (make <bar>)) => 42
> >
> > I expected:
> >
> >   (foo-a (make <bar>)) => bar

> Indeed, CLOS behaves as you expected...

Are you sure about that? I don't have a CLOS implementation 'at hand', and did not
have the time to carefully (re)read the hyperspec doc (my knowledge of it is quite
rusty now, it's been a very [very] long time since I studied it), but iirc, where
the slot list of a subclass must be computed as being the union of ..., I am not
sure it implies that a particular slot definition should result as the union of
getters, setters, accessors and any of the previously defined slot option actually.
Consider the following situation:

	(use-modules (oop goops))

	(define-class <foo> ()
	  (a #:accessor blue
	     #:allocation #:virtual
	     #:slot-ref (lambda (obj) 'foo)
	     #:slot-set! (lambda (obj val) (values))))

	(define-class <bar> (<foo>)
	  (a #:accessor red #:init-value 'bar))

	(class-slots <bar>)
	(class-slots <foo>)

	(define foo (make <foo>))
	(define bar (make <bar>))

	(blue bar)
	(red bar)
	(set! (blue bar) 'the-blue-bar)
	(set! (red bar) 'the-red-bar)
	(blue bar)
	(red bar)
	...

> I tried this example on both Guile 1.8 and Guile 1.6, and neither of
> them behave as you expected.  Instead they complain that there's no
> applicable method for 'foo-a'.

To me it is the right answer, the slot must be (re)defined, and not inherit any
previously defined slot options, but of course I might be wrong.

Cheers,
David



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-27 22:14   ` David Pirotte
@ 2014-04-28  1:12     ` Mark H Weaver
  2014-05-02  4:36       ` David Pirotte
  0 siblings, 1 reply; 12+ messages in thread
From: Mark H Weaver @ 2014-04-28  1:12 UTC (permalink / raw)
  To: David Pirotte; +Cc: guile-user

David Pirotte <david@altosw.be> writes:

> Hi Mark,
>
>> > When using GOOPS, if a class has a second slot, the #:getter procedure
>> > of the first slot returns the value of the second slot when applied to
>> > an instance of a subclass.
>> >
>> > (use-modules (oop goops))
>> >
>> > (define-class <foo> ()
>> >   (a #:init-form 'foo #:getter foo-a)
>> >   (b #:init-form 42))
>> >
>> > (define-class <bar> (<foo>)
>> >   (a #:init-form 'bar))
>> >
>> >   (foo-a (make <foo>)) => foo
>> >   (foo-a (make <bar>)) => 42
>> >
>> > I expected:
>> >
>> >   (foo-a (make <bar>)) => bar
>
>> Indeed, CLOS behaves as you expected...
>
> Are you sure about that?

Read this:

  http://clhs.lisp.se/Body/07_ec.htm

In particular:

 "In general, more than one class among C and its superclasses can
  define a slot with a given name.  In such cases, only one slot with
  the given name is accessible in an instance of C, and the
  characteristics of that slot are a combination of the several slot
  specifiers, computed as follows: [...]"

Here's a transcript of an SBCL session I tried on Debian:

--8<---------------cut here---------------start------------->8---
This is SBCL 1.0.57.0.debian, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (defclass foo ()
           ((a :initform 'foo :reader foo-a)
            (b :initform 42)))

#<STANDARD-CLASS FOO>
* (defclass bar (foo)
           ((a :initform 'bar)))

#<STANDARD-CLASS BAR>
* (values (foo-a (make-instance 'foo)) (foo-a (make-instance 'bar)))

FOO
BAR
--8<---------------cut here---------------end--------------->8---

Unknown_lamer on #guile tried the same thing with a different
implementation of Common Lisp, and got the same answer.

     Mark



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-28  1:12     ` Mark H Weaver
@ 2014-05-02  4:36       ` David Pirotte
  0 siblings, 0 replies; 12+ messages in thread
From: David Pirotte @ 2014-05-02  4:36 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-user

Hi Mark,

> Read this:
> 
>   http://clhs.lisp.se/Body/07_ec.htm

Perfect, thanks for the link and the confirmation.

Note that in the current implementation, guile's problem is not the [proper]
initialization of the inherited slot, as I did show and as you can check, slot-ref
works as expected on Diego's example.  One can also use describe for that matter
(oop goops describe) .. The problem is that getters, setters and accessors although
[merely] inherited are not properly recomputed.

Your temporary solution is nice, but only works if there is no need for a change
of the inherited slot allocation option, and would not solve the 'quantum
mechanic' slot states :) that my 'consider the following situation' example shows.

Therefore, in the mean time, I personally would recommend goops users to
redefine getters, setters and accessors they are using/plan to use on their
subclasse's instances, since it is currently the only way to 'force' guile to do
his job properly.

> Here's a transcript of an SBCL session I tried on Debian:

Yep, I've downloaded it too now, it's been a while I did not play with lisp :)  I
much prefer scheme and guile now.  But then I am not surprised they got it right,
for lispers clos is an old beast and  lisp implementations have, by far, much much
more code and many many more testers as well, indeed clos is so much more
used by lispers then goops by schemers.

Cheers,
David



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2014-04-25 23:24 #:getter procedure returns unexpected value in GOOPS Diogo F. S. Ramos
  2014-04-26 12:26 ` Neil Jerram
  2014-04-27  1:15 ` Mark H Weaver
@ 2015-03-09 21:58 ` Andy Wingo
  2015-04-23 22:56   ` David Pirotte
  2 siblings, 1 reply; 12+ messages in thread
From: Andy Wingo @ 2015-03-09 21:58 UTC (permalink / raw)
  To: Diogo F. S. Ramos; +Cc: guile-user

Hi!

On Sat 26 Apr 2014 01:24, "Diogo F. S. Ramos" <dfsr@riseup.net> writes:

> When using GOOPS, if a class has a second slot, the #:getter procedure
> of the first slot returns the value of the second slot when applied to
> an instance of a subclass.
>
> (use-modules (oop goops))
>
> (define-class <foo> ()
>   (a #:init-form 'foo #:getter foo-a)
>   (b #:init-form 42))
>
> (define-class <bar> (<foo>)
>   (a #:init-form 'bar))
>
>   (foo-a (make <foo>)) => foo
>   (foo-a (make <bar>)) => 42
>
> I expected:
>
>   (foo-a (make <bar>)) => bar

I realize this is really late :)  But since this thread isn't linked to
a bug, note that this is now fixed in stable-2.0 and master, to match
the behavior in Guile 1.8 and previous, which is actually that:

  (foo-a (make <bar>)) => error!

because <bar> doesn't just define a different init-value for the slot,
it defines a different slot entirely.

Andy
-- 
http://wingolog.org/



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

* Re: #:getter procedure returns unexpected value in GOOPS
  2015-03-09 21:58 ` Andy Wingo
@ 2015-04-23 22:56   ` David Pirotte
  0 siblings, 0 replies; 12+ messages in thread
From: David Pirotte @ 2015-04-23 22:56 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-user, Diogo F. S. Ramos

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

Hello Andy,

Le Mon, 09 Mar 2015 22:58:20 +0100,
Andy Wingo <wingo@pobox.com> a écrit :

> Hi!
> 
> On Sat 26 Apr 2014 01:24, "Diogo F. S. Ramos" <dfsr@riseup.net> writes:
> 
> > When using GOOPS, if a class has a second slot, the #:getter procedure
> > of the first slot returns the value of the second slot when applied to
> > an instance of a subclass.
> >
> > (use-modules (oop goops))
> >
> > (define-class <foo> ()
> >   (a #:init-form 'foo #:getter foo-a)
> >   (b #:init-form 42))
> >
> > (define-class <bar> (<foo>)
> >   (a #:init-form 'bar))
> >
> >   (foo-a (make <foo>)) => foo
> >   (foo-a (make <bar>)) => 42
> >
> > I expected:
> >
> >   (foo-a (make <bar>)) => bar
> 
> I realize this is really late :)  But since this thread isn't linked to
> a bug, note that this is now fixed in stable-2.0 and master, to match
> the behavior in Guile 1.8 and previous, which is actually that:
> 
>   (foo-a (make <bar>)) => error!
> 
> because <bar> doesn't just define a different init-value for the slot,
> it defines a different slot entirely.

I'm late too :)

I am afraid this was an unfortunate and quite terrible [design? I doubt] bug in
Guile-1.8 then. Indeed, even Stklos does correctly implement subclass slot
redefinition as specified by the clos protocol [*]

;;; subclass-slot-redefinition.scm starts here
(define-class <person> ()
  ((name :accessor name :init-keyword :name :init-form "")
   (age :accessor age :init-keyword :age :init-form -1)))

(define-class <teacher> (<person>)
  ((subject :accessor subject :init-keyword :subject :init-form "")))

(define-class <maths-teacher> (<teacher>)
  ((subject :init-form "Mathematics")))
;;; ends here

david@capac:~/alto/projects/stklos 8 $ stklos
*   STklos version 1.10
 *  Copyright (C) 1999-2011 Erick Gallesio - Universite de Nice <eg@unice.fr>
* * [Linux-3.16.0-4-amd64-x86_64/pthread/readline/utf8]
stklos> (load "subclass-slot-redefinition.scm")
stklos> (define p2 (make <maths-teacher> :name 'john :age 34))
;; p2
stklos> (describe p2)
#[<maths-teacher> b34420] is an an instance of class <maths-teacher>.
Slots are: 
     age = 34
     name = john
     subject = "Mathematics"
stklos> 

[*]

In summary, the clos protocol says:

	[ this is a copy/paste from a clos tutorial, also pointed by
	[ the Stklos reference manual:

	[	http://www.aiai.ed.ac.uk/~jeff/clos-guide.html#slots

	When there are superclasses, a subclass can specify a slot that has already
	been specified for a superclass. When this happens, the information in slot
	options has to be combined. For the slot options listed above, either the
	option in the subclass overrides the one in the superclass or there is a
	union:

	   :ACCESSOR  -  union
	   :INITARG   -  union
	   :INITFORM  -  overrides

	This is what you should expect. The subclass can change the default initial
	value by overriding the :initform, and can add to the initargs and accessors.

	However, the union for :accessor is just a consequence of how generic
	functions work. If they can apply to instances of a class C, they can also
	apply to instances of subclasses of C. (Accessor functions are generic.)

Note that the last sentence, which applies to getters and setters of course, is of
prime importance wrt our previous conversation and my reported bug about setters,
which must be inherited:

	wrt setters not being inherited, the current situation not only creates
	technical problems [it forces users to a [bad imo] programming style to
	overcome the bug] but it introduced a dual semantic for define-method and
	breaks this fundamental [language designed] rule: "... If they can apply to
	instances of a class C, they can also apply to instances of subclasses of
	C..."

Cheers,
David


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

end of thread, other threads:[~2015-04-23 22:56 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-25 23:24 #:getter procedure returns unexpected value in GOOPS Diogo F. S. Ramos
2014-04-26 12:26 ` Neil Jerram
2014-04-26 17:35   ` Diogo F. S. Ramos
2014-04-26 22:19     ` David Pirotte
2014-04-26 22:58       ` Diogo F. S. Ramos
2014-04-27 22:14         ` David Pirotte
2014-04-27  1:15 ` Mark H Weaver
2014-04-27 22:14   ` David Pirotte
2014-04-28  1:12     ` Mark H Weaver
2014-05-02  4:36       ` David Pirotte
2015-03-09 21:58 ` Andy Wingo
2015-04-23 22:56   ` David Pirotte

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