unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* goops - accessors, methods and generics
@ 2013-02-21 22:51 David Pirotte
  2013-02-22  1:16 ` Daniel Hartwig
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: David Pirotte @ 2013-02-21 22:51 UTC (permalink / raw)
  To: guile-devel

Hello all,

given the following 4 modules, I am facing what I consider an
inconsistent goops behavior and have one problem which leads to my
recurrent request of goops default behavior should be to [a] always
create a generic function for accessors and methods that do not [yet]
have one, visible in the entire guile space [all modules] and [b] the
default behavior should be '(merge-generics replace warn-override-core
warn last) [but that at least that one I can set using :duplicate, I know]

so, 2 or 3 things to show what happens and see what developers think.


1]

if i use in the repl or in my init.scm

  (default-duplicate-binding-handler '(merge-generics replace warn-override-core warn last))

->

	david@capac:~/gnu/kise 14 $ guile
	GNU Guile 2.0.7.9-21982
	...
	scheme@(guile-user)> (default-duplicate-binding-handler '(merge-generics replace warn-override-core warn last))
	scheme@(guile-user)> (use-modules (mg-3))
	(mg3/letstry)

	;;; note: source file /usr/alto/projects/gnu/tests/mg-3.scm
	;;;       newer than compiled /home/david/.cache/guile/ccache/2.0-LE-8-2.0/usr/alto/projects/gnu/tests/mg-3.scm.go
	;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
	;;;       or pass the --no-auto-compile argument to disable.
	;;; compiling /usr/alto/projects/gnu/tests/mg-3.scm
	WARNING: (mg-3): `dialog' imported from both (mg-1) and (mg-2)
	;;; compiled /home/david/.cache/guile/ccache/2.0-LE-8-2.0/usr/alto/projects/gnu/tests/mg-3.scm.go
	WARNING: (mg-3): `dialog' imported from both (mg-1) and (mg-2)
	ERROR: In procedure scm-error:
	ERROR: No applicable method for #<<accessor> dialog (1)> in call (dialog #<<widget-a> 1e97660>)


2]

if I uncomment the :duplicates block in mg-3, then it's fine 

	... ...
	;;; ("widget-a:" dialog-a)
	
	;;; ("widget-b:" dialog-b)
        scheme@(guile-user)> 


3]

what is more of a problem with the existing goops default, for me, is
expressed in the mg-4.scm 'case': i can not make it work unless I
manually create another module, manually making generics and make sure
it is loaded before ... or rename the accessors, which both solutions
are really against my expectation and [long] CLOS practice: why should
I have to manually do things which are inherent to oop [same name for
slots pertaining to different classes is so common that i can not see
any large application not having to do so, for semantic reasons].

unless i did miss that there is a way to ask goops to create a generic
fucntion for accessors and methods per default ?


scheme@(guile-user)> (use-modules (mg-4))
;;; note: source file /usr/alto/projects/gnu/tests/mg-4.scm
;;;       newer than compiled /home/david/.cache/guile/ccache/2.0-LE-8-2.0/usr/alto/projects/gnu/tests/mg-4.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /usr/alto/projects/gnu/tests/mg-4.scm
;;; compiled /home/david/.cache/guile/ccache/2.0-LE-8-2.0/usr/alto/projects/gnu/tests/mg-4.scm.go
scheme@(guile-user)> (mg4/letstry)
ERROR: In procedure scm-error:
ERROR: No applicable method for #<<accessor> dialog (1)> in call (dialog #<<widget-a> 23b7a60>)



;; cheers
cheers :)
David



;;mg-1.scm

(define-module (mg-1)
  :use-module (oop goops)

  :export (<widget-a>
	    dialog
	    make-widget-a))

(define-class <widget-a> ()
  (dialog #:accessor dialog #:init-keyword #:dialog #:init-value #f))

(define (make-widget-a)
  (make <widget-a> #:dialog 'dialog-a))


;; mg-2.scm

(define-module (mg-2)
  :use-module (oop goops)

  :export (<widget-b>
	    dialog
	    make-widget-b))


(define-class <widget-b> ()
  (dialog #:accessor dialog #:init-keyword #:dialog #:init-value #f))

(define (make-widget-b)
  (make <widget-b> #:dialog 'dialog-b))


;; mg3.scm

(define-module (mg-3)
  :use-module (oop goops)

  :use-module (mg-1)
  :use-module (mg-2)

  #!
  :duplicates (merge-generics 
	       replace
	       warn-override-core
	       warn
	       last)
  !#

  :export (mg3/letstry))

(define (mg3/letstry)
  (pk "widget-a:" (dialog (make-widget-a)))
  (pk "widget-b:" (dialog (make-widget-b)))
  (values))


;; mg-4.scm

(define-module (mg-4)
  :use-module (oop goops)
  :use-module (mg-1)

  :duplicates (merge-generics 
	       replace
	       warn-override-core
	       warn
	       last)

  :export (<widget-b>
	    dialog
	    make-widget-b
	    mg4/letstry))

(define-class <widget-b> ()
  (dialog #:accessor dialog #:init-keyword #:dialog #:init-value #f))

(define (make-widget-b)
  (make <widget-b> #:dialog 'dialog-b))

(define (mg4/letstry)
  (pk "widget-a:" (dialog (make-widget-a)))
  (pk "widget-b:" (dialog (make-widget-b))))



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

* Re: goops - accessors, methods and generics
  2013-02-21 22:51 goops - accessors, methods and generics David Pirotte
@ 2013-02-22  1:16 ` Daniel Hartwig
  2013-02-22 23:11   ` David Pirotte
  2013-02-23 11:20 ` Stefan Israelsson Tampe
  2013-02-23 11:44 ` Stefan Israelsson Tampe
  2 siblings, 1 reply; 9+ messages in thread
From: Daniel Hartwig @ 2013-02-22  1:16 UTC (permalink / raw)
  To: David Pirotte; +Cc: guile-devel

Hi

It seems you are expecting some CLOS behaviour in a language that can
not support it.  The accessors are generic functions, but each of your
modules creates a unique generic function, there is no implicit
namespace sharing in Scheme.  Define a base module with an appropriate
superclass or interface definition (generics); Scheme requires it.

On 22 February 2013 06:51, David Pirotte <david@altosw.be> wrote:
> Hello all,
>
> given the following 4 modules, I am facing what I consider an
> inconsistent goops behavior and have one problem which leads to my
> recurrent request of goops default behavior should be to

> [a] always
> create a generic function for accessors and methods that do not [yet]
> have one, *visible in the entire guile space [all modules]*

Note that <generic> is a superclass of <accessor>, so these are
already generic functions.  There is no global binding escalation in
Scheme.

Consider these situations followed by introducing any of your example
class definitions:
- module A binds ‘define’ to a non-procedure; or
- modules B and C bind ‘define’ to different procedures.

Your suggestion is appropriate in a language like Common Lisp with
dynamic scoping, and separate namespaces for function and non-function
bindings.  Not so appropriate for Scheme.

In your example the two classes share a common interface, but this
interface is never defined anywhere.  So if I have code that wants to
work with any widget, which module should be imported to get the
canonical interface definition?  Indeed, it will either have to be
created using a common superclass or manually defined generics (as you
later observe).  These widget implementations will then have to import
the base module to explicitly share in the interface.

> and [b] the
> default behavior should be '(merge-generics replace warn-override-core
> warn last) [but that at least that one I can set using :duplicate, I know]

The default behaviour is conservative with regards to namespace
separation.  If you desire this behaviour it seems best to explicitly
ask for it.  With CLOS a different default can be expected to apply
because bindings in the underlying language already work in a similar
way.

> what is more of a problem with the existing goops default, for me, is
> expressed in the mg-4.scm 'case': i can not make it work unless I
> manually create another module, manually making generics and make sure
> it is loaded before ...

In a language like Scheme this can not be avoided.  Namespaces must be
managed quite explicitly.

In your example, mg-1 and mg-2 are not sharing any bindings.  It is
not appropriate to assume that ‘dialog’ in either is related to the
other.  If they implement a common interface, as seems obvious in the
example, then they need to import the generic bindings for that from
a common base module.  Such a module should either define a superclass
or you can manually define the generics.

> or rename the accessors, which both solutions
> are really against my expectation and [long] CLOS practice: why should
> I have to manually do things which are inherent to oop [same name for
> slots pertaining to different classes is so common that i can not see
> any large application not having to do so, for semantic reasons].

GOOPS can not do everything the same as CLOS due to fundamental
differences between the underlying languages.

If the interface is the same, you have a candidate for superclass.
Either way, any code that hopes to use the (generic) interface needs
to import the bindings from somewhere, and that will be a module
containing either a superclass or a set of manually defined generics.

Regards



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

* Re: goops - accessors, methods and generics
  2013-02-22  1:16 ` Daniel Hartwig
@ 2013-02-22 23:11   ` David Pirotte
  2013-02-23  0:37     ` Daniel Hartwig
  0 siblings, 1 reply; 9+ messages in thread
From: David Pirotte @ 2013-02-22 23:11 UTC (permalink / raw)
  To: Daniel Hartwig; +Cc: guile-devel

Hi Daniel,

thanks for your answer, but where i understand a strict name space will lead to
merging the generic(s) from/with the ones that comes from the modules you are
importing [as opposed to a general 'goops' name space], i disagree that this would be
a 'pre limitation' that provides a proper handling of the problem we are talking
about.

> Note that <generic> is a superclass of <accessor>, so these are
> already generic functions. 

great, so the interface is defined, right?

> Consider these situations followed by introducing any of your example
> class definitions:
> - module A binds ‘define’ to a non-procedure; or
> - modules B and C bind ‘define’ to different procedures.

let's stick to goops, shall we

> In your example the two classes share a common interface, but this
> interface is never defined anywhere.

you just said above that it is, at least for accessors: i am also defending the idea
that it should always automatically create a generic function [for methods as well]
if none exists.

> So if I have code that wants to  work with any widget, which module should be
> imported to get the canonical interface definition?

the canonical definition comes from the first imported module that [also] defines
the generic: this is what occurs in the mg-3.scm example, and that actually works
fine, as you know.

however in the mg-4 example, it does not, which i think is an implementation
problem: since i am asking guile to merge... it should import mg-1 and merge its own
generics with the imported ones. there is no reason, and certainly not the name
space conservativness, why this is not properly implemented in guile.

> If the interface is the same, you have a candidate for superclass.

yes, that is a possibility, and in some cases i agree that it is the way to go, but
it should not be imposed on the user.

Cheers,
David



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

* Re: goops - accessors, methods and generics
  2013-02-22 23:11   ` David Pirotte
@ 2013-02-23  0:37     ` Daniel Hartwig
  2013-03-05 23:30       ` David Pirotte
  0 siblings, 1 reply; 9+ messages in thread
From: Daniel Hartwig @ 2013-02-23  0:37 UTC (permalink / raw)
  To: David Pirotte; +Cc: guile-devel

On 23 February 2013 07:11, David Pirotte <david@altosw.be> wrote:
> Hi Daniel,
>
> thanks for your answer, but where i understand a strict name space will lead to
> merging the generic(s) from/with the ones that comes from the modules you are
> importing [as opposed to a general 'goops' name space], i disagree that this would be
> a 'pre limitation' that provides a proper handling of the problem we are talking
> about.

Right, I had misread part of your initial message by focusing on the
lack of a superclass.  However, other comments still stand.

Indeed it would not pose any namespacing issues in this way that you
clarify.  However, by not declaring a base module with a superclass in
it you are needless complicating interaction with this set of modules.

>
>> Note that <generic> is a superclass of <accessor>, so these are
>> already generic functions.
>
> great, so the interface is defined, right?

: (eq? (@ (mg-1) dialog)
:      (@ (mg-2) dialog))
: =>
: #f

There is no *common* interface defined.  These modules merely provide
interfaces with the same names.  Both of the above bindings are
generics, yes, but they are not the same generic because you have not
taken care to share one generic with the other module.  This is the
root of your problems.

A generic is a generic, and can have multiple methods defined on it,
yes.  But scoping concerns must absolutely prevent automagically
assuming that a method in mg-2 should be added to a generic in mg-1.
mg-2 must explicitly import that generic if it wants to use it,
otherwise you get two.  Once you get two distinct generics you begin
to have the problems you see.

You later suggest to import multiple modules and use merge-generics,
but that is highly impractical for a user and yourself.  By doing so
you also risk subtle bugs hiding amongst yours and user modules.

Consider a user that only imports mg-2, but some how ends up receiving
a <widget-a>.  They will not be able to operate on that object without
subsequently importing mg-1 and taking care to merge the generics.

>> In your example the two classes share a common interface, but this
>> interface is never defined anywhere.
>
> you just said above that it is, at least for accessors:

No, the common interface is not *defined* anywhere.  They have similar
yet distinct interfaces.

Other than failure to use a superclass and share generics from a
common base module, your real problem with mg-4 lies in the failure to
re-export the binding of dialog.  Also, merge-generics is not required
there since it only applies to duplicate imports.

-- mg-4.scm:
(define-module (mg-4)
  :use-module (oop goops)
  :use-module (mg-1)

  :export (<widget-b>
            make-widget-b
            mg4/letstry)

  :re-export (dialog))

(define-class <widget-b> ()
  (dialog #:accessor dialog #:init-keyword #:dialog #:init-value #f))

(define (make-widget-b)
  (make <widget-b> #:dialog 'dialog-b))

(define (mg4/letstry)
  (pk "widget-a:" (dialog (make-widget-a)))
  (pk "widget-b:" (dialog (make-widget-b))))
--

> i am also defending the idea
> that it should always automatically create a generic function [for methods as well]
> if none exists.

Methods are always for generic functions.  They operate no other way.

>
>> So if I have code that wants to  work with any widget, which module should be
>> imported to get the canonical interface definition?
>
> the canonical definition comes from the first imported module that [also] defines
> the generic: this is what occurs in the mg-3.scm example, and that actually works
> fine, as you know.

You are talking about merge-generics, I am talking about a publicly
defined common interface.  These are not the same.  As I mention
earlier, what should a user import when they want accessors for all
widgets?  With your example, they will have to specifically import
every widget-X module *and merge-generics* just to get at a common
enough interface.

With a base module making the common interface explicit, there is only
one module to import and you can handle widgets of any class.

> however in the mg-4 example, it does not, which i think is an implementation
> problem: since i am asking guile to merge... it should import mg-1 and merge its own
> generics with the imported ones. there is no reason, and certainly not the name
> space conservativness, why this is not properly implemented in guile.

See above.

Your issues are trivially avoided by using a superclass, which is
sound design practice anyway.  Within a family of modules, using
merge-generics immediately signals the presence of design issues.

Regards



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

* Re: goops - accessors, methods and generics
  2013-02-21 22:51 goops - accessors, methods and generics David Pirotte
  2013-02-22  1:16 ` Daniel Hartwig
@ 2013-02-23 11:20 ` Stefan Israelsson Tampe
  2013-02-23 11:44 ` Stefan Israelsson Tampe
  2 siblings, 0 replies; 9+ messages in thread
From: Stefan Israelsson Tampe @ 2013-02-23 11:20 UTC (permalink / raw)
  To: guile-devel; +Cc: David Pirotte

I don't find the behavior strange.

1. Declaring dialog generic in mg-1 and mg-2 and merge generics in
mg-3 solves the mg-3 case.

2. When exporting dialog in mg-4 the system automatically undefine the
dialog symbol imported. By in stead using :re-export (dialog) the mg-4 
case
is solved.

The question if we should automatically always merge generics and
automatically always define accessors generic I do not agree. The
reason is that the current approach is more general. On the other hand
as we saw subtle bugs can appear and a good warning/diagnosing system
that can help pinpoint these issues would indeed be a good additions.

/Stefan

On Thursday, February 21, 2013 07:51:39 PM David Pirotte wrote:
> Hello all,
> 
> given the following 4 modules, I am facing what I consider an
> inconsistent goops behavior and have one problem which leads to my
> recurrent request of goops default behavior should be to [a] always
> create a generic function for accessors and methods that do not [yet]
> have one, visible in the entire guile space [all modules] and [b] the
> default behavior should be '(merge-generics replace warn-override-core
> warn last) [but that at least that one I can set using :duplicate, I
> know]
> 
> so, 2 or 3 things to show what happens and see what developers think.
> 
> 
> 1]
> 
> if i use in the repl or in my init.scm
> 
>   (default-duplicate-binding-handler '(merge-generics replace
> warn-override-core warn last))
> 
> ->
> 
> 	david@capac:~/gnu/kise 14 $ guile
> 	GNU Guile 2.0.7.9-21982
> 	...
> 	scheme@(guile-user)> (default-duplicate-binding-handler
> '(merge-generics replace warn-override-core warn last))
> scheme@(guile-user)> (use-modules (mg-3))
> 	(mg3/letstry)
> 
> 	;;; note: source file /usr/alto/projects/gnu/tests/mg-3.scm
> 	;;;       newer than compiled
> /home/david/.cache/guile/ccache/2.0-LE-8-2.0/usr/alto/projects/gnu/te
> sts/mg-3.scm.go ;;; note: auto-compilation is enabled, set
> GUILE_AUTO_COMPILE=0 ;;;       or pass the --no-auto-compile argument
> to disable. ;;; compiling /usr/alto/projects/gnu/tests/mg-3.scm
> 	WARNING: (mg-3): `dialog' imported from both (mg-1) and (mg-2)
> 	;;; compiled
> /home/david/.cache/guile/ccache/2.0-LE-8-2.0/usr/alto/projects/gnu/te
> sts/mg-3.scm.go WARNING: (mg-3): `dialog' imported from both (mg-1)
> and (mg-2) ERROR: In procedure scm-error:
> 	ERROR: No applicable method for #<<accessor> dialog (1)> in call
> (dialog #<<widget-a> 1e97660>)
> 
> 
> 2]
> 
> if I uncomment the :duplicates block in mg-3, then it's fine
> 
> 	... ...
> 	;;; ("widget-a:" dialog-a)
> 
> 	;;; ("widget-b:" dialog-b)
>         scheme@(guile-user)>
> 
> 
> 3]
> 
> what is more of a problem with the existing goops default, for me, is
> expressed in the mg-4.scm 'case': i can not make it work unless I
> manually create another module, manually making generics and make sure
> it is loaded before ... or rename the accessors, which both solutions
> are really against my expectation and [long] CLOS practice: why
> should I have to manually do things which are inherent to oop [same
> name for slots pertaining to different classes is so common that i
> can not see any large application not having to do so, for semantic
> reasons].
> 
> unless i did miss that there is a way to ask goops to create a generic
> fucntion for accessors and methods per default ?
> 
> 
> scheme@(guile-user)> (use-modules (mg-4))
> ;;; note: source file /usr/alto/projects/gnu/tests/mg-4.scm
> ;;;       newer than compiled
> /home/david/.cache/guile/ccache/2.0-LE-8-2.0/usr/alto/projects/gnu/te
> sts/mg-4.scm.go ;;; note: auto-compilation is enabled, set
> GUILE_AUTO_COMPILE=0 ;;;       or pass the --no-auto-compile argument
> to disable. ;;; compiling /usr/alto/projects/gnu/tests/mg-4.scm
> ;;; compiled
> /home/david/.cache/guile/ccache/2.0-LE-8-2.0/usr/alto/projects/gnu/te
> sts/mg-4.scm.go scheme@(guile-user)> (mg4/letstry)
> ERROR: In procedure scm-error:
> ERROR: No applicable method for #<<accessor> dialog (1)> in call
> (dialog #<<widget-a> 23b7a60>)
> 
> 
> 
> ;; cheers
> cheers :)
> David
> 
> 
> 
> ;;mg-1.scm
> 
> (define-module (mg-1)
> 
>   :use-module (oop goops)
>   :
>   :export (<widget-a>
> 
> 	    dialog
> 	    make-widget-a))
> 
> (define-class <widget-a> ()
>   (dialog #:accessor dialog #:init-keyword #:dialog #:init-value #f))
> 
> (define (make-widget-a)
>   (make <widget-a> #:dialog 'dialog-a))
> 
> 
> ;; mg-2.scm
> 
> (define-module (mg-2)
> 
>   :use-module (oop goops)
>   :
>   :export (<widget-b>
> 
> 	    dialog
> 	    make-widget-b))
> 
> 
> (define-class <widget-b> ()
>   (dialog #:accessor dialog #:init-keyword #:dialog #:init-value #f))
> 
> (define (make-widget-b)
>   (make <widget-b> #:dialog 'dialog-b))
> 
> 
> ;; mg3.scm
> 
> (define-module (mg-3)
> 
>   :use-module (oop goops)
>   :
>   :use-module (mg-1)
>   :use-module (mg-2)
> 
>   #!
> 
>   :duplicates (merge-generics
> 
> 	       replace
> 	       warn-override-core
> 	       warn
> 	       last)
>   !#
> 
>   :export (mg3/letstry))
> 
> (define (mg3/letstry)
>   (pk "widget-a:" (dialog (make-widget-a)))
>   (pk "widget-b:" (dialog (make-widget-b)))
>   (values))
> 
> 
> ;; mg-4.scm
> 
> (define-module (mg-4)
> 
>   :use-module (oop goops)
>   :use-module (mg-1)
>   :
>   :duplicates (merge-generics
> 
> 	       replace
> 	       warn-override-core
> 	       warn
> 	       last)
> 
>   :export (<widget-b>
> 
> 	    dialog
> 	    make-widget-b
> 	    mg4/letstry))
> 
> (define-class <widget-b> ()
>   (dialog #:accessor dialog #:init-keyword #:dialog #:init-value #f))
> 
> (define (make-widget-b)
>   (make <widget-b> #:dialog 'dialog-b))
> 
> (define (mg4/letstry)
>   (pk "widget-a:" (dialog (make-widget-a)))
>   (pk "widget-b:" (dialog (make-widget-b))))




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

* Re: goops - accessors, methods and generics
  2013-02-21 22:51 goops - accessors, methods and generics David Pirotte
  2013-02-22  1:16 ` Daniel Hartwig
  2013-02-23 11:20 ` Stefan Israelsson Tampe
@ 2013-02-23 11:44 ` Stefan Israelsson Tampe
  2 siblings, 0 replies; 9+ messages in thread
From: Stefan Israelsson Tampe @ 2013-02-23 11:44 UTC (permalink / raw)
  To: guile-devel; +Cc: David Pirotte

For the mg-3 case, Actually, only (merge-generics) in mg-3 is needed, 
the
accessors are automatically generics.

/Stefan




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

* Re: goops - accessors, methods and generics
  2013-02-23  0:37     ` Daniel Hartwig
@ 2013-03-05 23:30       ` David Pirotte
  2013-03-06  0:28         ` Mark H Weaver
  2013-03-06 14:15         ` Ludovic Courtès
  0 siblings, 2 replies; 9+ messages in thread
From: David Pirotte @ 2013-03-05 23:30 UTC (permalink / raw)
  To: Daniel Hartwig; +Cc: guile-devel

Hello,

> Right, I had misread part of your initial message by focusing on the
> lack of a superclass.

there is no lack of superclass, your are giving your opinion, which is fine, but i
didn't ask, and actually it is a bad opinion: you don't want to [and don't have to
by clos spec] create a superclass just because of 1 or 2 slot names. besides, this is
a small example, in a large scale system, you may not even know  if other classes
already ... [and should not need to of course, clos/goops is precisly designed to
handle this basic and very common situation].

> However, by not declaring a base module with a superclass in  it you are needless
> complicating interaction with this set of modules.

no, what needlessly complicates things is the unfortunate decision of guilers to
mix goops with the module system:  you do not want any [by far inferior] module
system to interfere with clos/goops. since then you end-up with multiple generics, a
pure non sense. then users/developers, like you, start to re-interpret clos, in a
wrong way, saying that 'there is no common interface' :) of course there is,
'define-class ... dialog...' twice, on purpose, but guile 'broke it', in the name of
its module system, against the clos/goops paradigm.

if at least guile designers and goops implementors would have provided a 'switch'
so that we could ask that any and all goops related stuff being in a single name
space available 'anywhere' at all time [such as guile core functionality is], it
would be great, but reading you, it sounds it is more like a religion problem: not
much we can do when it comes to that. 

> You later suggest to import multiple modules and use merge-generics,
> but that is highly impractical for a user and yourself.

of course, no one should ever merge generics, there should be a single name space
for goops stuff.

but given it is not the case, what is actually impracticle, for anybody, is the
[rather perverse] hidden behavior of guile's module system when I ask to export my
accessors [i should always be able to export an accessor i just defined, and never
forced to know if someone else also did...]: in this case, i obviously expect the
'importer' to receive at the very least what the module that exports has [such as
#<<accessor> dialog (2)>] but hopefully the 'extended generic with setter'. at the
contrary, guile seems to destroy [or recreate?] and export a single class capable
accessor: to my opinion, this is a bug [and the worst language core hidden behavior
i ever faced in my career: i still can not believe it actually: why on earth guile
thinks he knows better then i].

> Consider a user that only imports mg-2, but some how ends up receiving
> a <widget-a>.  They will not be able to operate on that object without
> subsequently importing mg-1 and taking care to merge the generics.

mg-2 should export the generic, as opposed to a single class capable accessor. once
more, clos/goops do not need a module system, if that is the case, it is because you
have a bad oop design and should redesign it better.

> >> In your example the two classes share a common interface, but this
> >> interface is never defined anywhere.

it should, automatically be created, see clos spec: since i use define-class and
give the accessor the same name, it must obviously consider one generic function and
add the methods appropriatly. export, from any module, should always export the
generic, then import always always work.

> No, the common interface is not *defined* anywhere.  They have similar
> yet distinct interfaces.

then it is a bug caused by the module system interfering with my design, but i
obviously want and have written the source code that asks for a common interface:
'define-class ... dialog ...' twice, on purpose. i do not want to write extra code
and/or modules, i don't want a superclass for this case.

> your real problem with mg-4 lies in the failure to re-export the binding of
> dialog.  

and here comes the real bug i am facing: a guile bug, not a bug of mine: as said
above, i should never have to know whether someone else in his modules, also has
used and exported the accessor name. i should always be able to export what i define
in my module _and_ guile should always export the generic 

> Methods are always for generic functions.  They operate no other way.

sure, i ment one generic per name for the entire system, not per module..

> You are talking about merge-generics, I am talking about a publicly
> defined common interface.  These are not the same. 

clos/goops defines the common interface mechanism. by mixing with the guile module
system, you destroy this mechanism, than the hidden bug(s) we are talking about that
should never appear of course.

> what should a user import when they want accessors for all widgets?  With your
> example, they will have to specifically import every widget-X module *and
> merge-generics* just to get at a common enough interface.

chances are that this user also wants the all module functionality, not just the
'common' accessors. he obviously will import all the modules that he needs and works
with the public interface of each of them. he should not have to merge anything, i
merge [since i am forced to] and export, he receives generics.

> With a base module making the common interface explicit, there is only
> one module to import and you can handle widgets of any class.

that will only work in a small system, not a large scale one where you do not know
'everything'. the small example i gave was actually just an example, but it will
happen in a real and further more large to very large system.

> Within a family of modules, using merge-generics immediately signals the presence
> of design issues.

the design issue comes from the mixing of the module system with goops and since
right now we have no option, the bug in not properly exporting the generic or at
least the 'multiple class capable' accessor(s). this export bug also affects defining
methods on existing 'core' generics [like get/set which comes with the
guile-gnome-platform.

Cheers,
David






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

* Re: goops - accessors, methods and generics
  2013-03-05 23:30       ` David Pirotte
@ 2013-03-06  0:28         ` Mark H Weaver
  2013-03-06 14:15         ` Ludovic Courtès
  1 sibling, 0 replies; 9+ messages in thread
From: Mark H Weaver @ 2013-03-06  0:28 UTC (permalink / raw)
  To: David Pirotte; +Cc: guile-devel

Hi David,

David Pirotte <david@altosw.be> writes:
> no, what needlessly complicates things is the unfortunate decision of guilers to
> mix goops with the module system:  you do not want any [by far inferior] module
> system to interfere with clos/goops. [...]
[...]
> if at least guile designers and goops implementors would have provided a 'switch'
> so that we could ask that any and all goops related stuff being in a single name
> space available 'anywhere' at all time [such as guile core functionality is],

No, guile core functionality is *not* in a single name space.  It is in
the (guile) module.

There are several problems with your proposal.  First of all, there's no
syntactic distinction between generic function calls and ordinary
procedure calls.  For that matter, in Scheme the operator position of a
procedure call is evaluated in the same way as any other expression.

So, in the context of Scheme, what you're suggesting essentially boils
down to this: every *variable* lookup would have to first look in your
"single name space" before looking anywhere else.

But let's set this (very serious) problem aside for the moment.
I want to explain the reason why I believe a "single name space" is
fundamentally a bad idea, even if generic function calls *could* be
syntactically distinguished.

Suppose Bob uses GOOPS to write a component for drawing things on a text
display using curses.  He defines a 'draw' generic function, and add
several methods to it, including methods to render all of the standard
Scheme types such as lists, vectors, and strings.

Now suppose that Alice uses GOOPS to write a component that also defines
a 'draw' generic function, but with very different semantics.  Alice
adds her own methods to 'draw' the standard Scheme types.

The module system allows these two components to coexist in the same
system without those two 'draw' generic functions from interfering with
each other.  This in turn allows hackers to use short names such as
"draw", "ref", "x", etc, without fear of unintended conflicts.

What's worse: under your proposal, if conflicts arose between modules,
there's no easy way to fix it.  You'd have to rename the generic
functions in one of the components to avoid the conflict.  In practice,
people experienced with such a system would eventually learn that they
must pick long variable names and cross their fingers, just as people
did in the bad old days of dynamically-scoped variables.

So that's the argument in favor of the module system.  What's the
argument on the other side?  Apparently, it's that you find it
inconvenient to define your interfaces (generic functions) in a separate
module and to import that module in all of your other modules.

To my mind, the arguments in favor of the module system are *far* more
compelling than those of the other side.

I'm sorry that you chose to characterize our position as "religion".
Personally, I found that very disrespectful.

     Mark



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

* Re: goops - accessors, methods and generics
  2013-03-05 23:30       ` David Pirotte
  2013-03-06  0:28         ` Mark H Weaver
@ 2013-03-06 14:15         ` Ludovic Courtès
  1 sibling, 0 replies; 9+ messages in thread
From: Ludovic Courtès @ 2013-03-06 14:15 UTC (permalink / raw)
  To: guile-devel

David Pirotte <david@altosw.be> skribis:

> if at least guile designers and goops implementors would have provided a 'switch'
> so that we could ask that any and all goops related stuff being in a single name
> space available 'anywhere' at all time [such as guile core functionality is], it
> would be great, but reading you, it sounds it is more like a religion problem: not
> much we can do when it comes to that. 

One problem with GOOPS is that it changes Guile’s behavior globally,
which is not always desirable.

It also introduces run-time and memory overhead here and there.  For
instance, “guile -c '(use-modules (oop goops))'” executes in ~70 ms on
my machine, vs. ~25 ms for “guile -c 1”.

My 2¢,
Ludo’.




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

end of thread, other threads:[~2013-03-06 14:15 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-02-21 22:51 goops - accessors, methods and generics David Pirotte
2013-02-22  1:16 ` Daniel Hartwig
2013-02-22 23:11   ` David Pirotte
2013-02-23  0:37     ` Daniel Hartwig
2013-03-05 23:30       ` David Pirotte
2013-03-06  0:28         ` Mark H Weaver
2013-03-06 14:15         ` Ludovic Courtès
2013-02-23 11:20 ` Stefan Israelsson Tampe
2013-02-23 11:44 ` Stefan Israelsson Tampe

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