unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Modules and GOOPS
@ 2016-07-27 17:53 Kovacsics Róbert
  2016-07-27 19:44 ` Jan Wedekind
  2016-07-28 21:14 ` David Pirotte
  0 siblings, 2 replies; 11+ messages in thread
From: Kovacsics Róbert @ 2016-07-27 17:53 UTC (permalink / raw)
  To: guile-user

Hello!

I have trouble with getting GOOPS and modules to co-operate. What I am
trying to do is to have 'A subclass B' where A is something akin to an
abstract class, that is it has generic "x" for which it provides no
implementation. This is my minimum broken example:


; <mbe/a.scm>=
(define-module (mbe a)
  #:use-module (oop goops)
  #:export (<a> x y))

(define-class <a> ())

(define-generic x)
(define-generic y)

(define-method (y (a <a>))
  (display (x a)))

; <mbe/b.scm>=
(define-module (mbe b)
  #:use-module (oop goops)
  #:use-module (mbe a)
  #:export (<b> x))

(define-class <b> (<a>))

(define-method (x (b <b>))
  'b)

; <mbe/test.scm>=
(define-module (mbe test)
  #:use-module (oop goops)
  #:use-module (mbe a)
  #:use-module (mbe b)
  #:duplicates (merge-generics))

(y (make <b>))


and when I type "(use-modules (mbe test))" in guile, I get


While compiling expression:
ERROR: No applicable method for #<<generic> x (0)> in call (x #<<b> 23ccdd0>)

(which shows that the generic function "x" has no implementation as
far as I can work it out, due to accessibility. When I don't use
separate modules, it works.)

Am I using the right sort of approach? I was thinking modules, for
extensibility.



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

* Re: Modules and GOOPS
  2016-07-27 17:53 Modules and GOOPS Kovacsics Róbert
@ 2016-07-27 19:44 ` Jan Wedekind
  2016-07-28 22:36   ` David Pirotte
  2016-07-28 21:14 ` David Pirotte
  1 sibling, 1 reply; 11+ messages in thread
From: Jan Wedekind @ 2016-07-27 19:44 UTC (permalink / raw)
  To: Kovacsics Róbert; +Cc: guile-user

On Wed, 27 Jul 2016, Kovacsics Róbert wrote:

> Hello!
>
> I have trouble with getting GOOPS and modules to co-operate. What I am
> trying to do is to have 'A subclass B' where A is something akin to an
> abstract class, that is it has generic "x" for which it provides no
> implementation. This is my minimum broken example:
>
>
> ; <mbe/a.scm>=
> (define-module (mbe a)
>  #:use-module (oop goops)
>  #:export (<a> x y))
>
> (define-class <a> ())
>
> (define-generic x)
> (define-generic y)
>
> (define-method (y (a <a>))
>  (display (x a)))
>
> ; <mbe/b.scm>=
> (define-module (mbe b)
>  #:use-module (oop goops)
>  #:use-module (mbe a)
>  #:export (<b> x))
>
> (define-class <b> (<a>))
>
> (define-method (x (b <b>))
>  'b)
>
> ; <mbe/test.scm>=
> (define-module (mbe test)
>  #:use-module (oop goops)
>  #:use-module (mbe a)
>  #:use-module (mbe b)
>  #:duplicates (merge-generics))
>
> (y (make <b>))
>
>
> and when I type "(use-modules (mbe test))" in guile, I get
>
>
> While compiling expression:
> ERROR: No applicable method for #<<generic> x (0)> in call (x #<<b> 23ccdd0>)
>
> (which shows that the generic function "x" has no implementation as
> far as I can work it out, due to accessibility. When I don't use
> separate modules, it works.)
>
> Am I using the right sort of approach? I was thinking modules, for
> extensibility.
>
>

Having mbe/b.scm *not* export "x" works but I am not sure whether that is 
the solution you are looking for:


; <mbe/a.scm>=
(define-module (mbe a)
   #:use-module (oop goops)
   #:export (<a> x y))

(define-class <a> ())

(define-generic x)
(define-generic y)

(define-method (y (a <a>))
   (display (x a)))

; <mbe/b.scm>=
(define-module (mbe b)
   #:use-module (oop goops)
   #:use-module (mbe a)
   #:export (<b>))

(define-class <b> (<a>))

(define-method (x (b <b>))
   'b)

; <mbe/test.scm>=
(define-module (mbe test)
   #:use-module (oop goops)
   #:use-module (mbe a)
   #:use-module (mbe b)
   #:duplicates (merge-generics))

(y (make <b>))


Has anybody managed to get the "merge-generics" handler to work? I used to 
have this in my $HOME/.guile configuration but it didn't seem to have any 
effect:

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


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

* Re: Modules and GOOPS
  2016-07-27 17:53 Modules and GOOPS Kovacsics Róbert
  2016-07-27 19:44 ` Jan Wedekind
@ 2016-07-28 21:14 ` David Pirotte
  2016-07-29  5:17   ` David Pirotte
  2016-07-29 17:00   ` Kovacsics Róbert
  1 sibling, 2 replies; 11+ messages in thread
From: David Pirotte @ 2016-07-28 21:14 UTC (permalink / raw)
  To: Kovacsics Róbert; +Cc: guile-user

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

Hello,

Before anything else, note that I speak on my own behalf here, not in the name of
Guile. I'm saying this because I have an opinionated opinion about Goops, its actual
'design/problems/limitations/bugs' [depending of your point of view], why and how we
should change this, as well as how users should use it, precisely regarding, but not
limited to, generic functions and the module system, among other things.

> I have trouble with getting GOOPS and modules to co-operate. What I am
> trying to do is to have 'A subclass B' where A is something akin to an
> abstract class, that is it has generic "x" for which it provides no
> implementation. This is my minimum broken example:

First, generic functions are 'containers', that are not associated, and do not
pertain to any class. <a> does not have a generic function x:

	obviously, this _is_ the beauty (and one of the reason why it's been design
	this way) since this way, the entire knowledge, except for slot-ref and
	slot-set! [1] of a generic function multi method polymorphic dispatch system
	is in user methods and procedures called by these methods;

	this means, unlike it's been said on this ML several time, unless you use
	slot-set! (same for Guile set!, no diff wrt Goops here) and  class
	redefinition, Goops is perfectly 'compatible' with functional programming;

	[1] same problem for define-record, which are not more neither less
	'functional' then Goops, imo.

Then unlike you've been told by others, I do not recommend to define generic
function, they are just 'containers', the system creates them for you and it is an
error [not implemented by Guile] to redefine a generic function. With the last in
mind, manually defining GF will work if you play with a couple of your own modules,
but it will almost certainly fail for large system.

But if you do so, define generic functions manually, then I recommend do it in
another module.

> ; <mbe/a.scm>=
> (define-module (mbe a)
>   #:use-module (oop goops)
>   #:export (<a> x y))
> 
> (define-class <a> ())
> 
> (define-generic x)
> (define-generic y)
> 
> (define-method (y (a <a>))
>   (display (x a)))
> 
> ; <mbe/b.scm>=
> (define-module (mbe b)
>   #:use-module (oop goops)
>   #:use-module (mbe a)
>   #:export (<b> x))

It will work if you #:re-export (x):

	#:export (<b>)
	#:re-export (x))

But that not good enough, imo. We precisely _do not_ want to know if we have to use
#:export or #:re-export, what we want here is the system to do that for us. I wrote
a macro which does the check 'if-exists' for us and either #:export or #:re-export
adequately, it's here, fell free to use it:

	http://git.savannah.gnu.org/cgit/grip.git/tree/grip/g-export.scm

You should use it _only_ for getters, setters, accessors and methods, obviously!

 	here is an example of use

	http://git.savannah.gnu.org/cgit/grip.git/tree/grip/clutter/grid.scm

Make sure your class names are unique i the entire 'system' and always use #:export
<class name>: this will always create a fresh new binding, and so, unlike in CLOS,
won't trigger a class redefinition if it would need to.  This said, unless you
really know what you're doing, or for pure experimental reasons, don't write
'production' code that rely on class redefinition.

> (define-class <b> (<a>))
> 
> (define-method (x (b <b>))
>   'b)
> 
> ; <mbe/test.scm>=
> (define-module (mbe test)
>   #:use-module (oop goops)
>   #:use-module (mbe a)
>   #:use-module (mbe b)
>   #:duplicates (merge-generics))

You should add merge-generics to the default handlers:

	scheme@(guile-user)> (default-duplicate-binding-handler)
	$5 = (replace warn-override-core warn last)

So you'd have 

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

Note that you still have to set these in your repl (and any script of yours), if you
import more then 1 module defining a GF.  Here is an example of script:

	http://git.savannah.gnu.org/cgit/grip.git/tree/grip/clutter/examples/bouncer.in
	
		[ line 38 - 41

Also note that in Guile-2.0, module definitions (ice-9/boot.scm
define-modules* macro) were calling (default-duplicate-binding-handler), so it
was not necessary to declare #:duplicates in each module. This great global
parameter setting, and API IMO, has been withdrawn in Guile-2.2, which hard codes
duplicate handlers 'as in the manual'.

David.

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

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

* Re: Modules and GOOPS
  2016-07-27 19:44 ` Jan Wedekind
@ 2016-07-28 22:36   ` David Pirotte
  0 siblings, 0 replies; 11+ messages in thread
From: David Pirotte @ 2016-07-28 22:36 UTC (permalink / raw)
  To: Jan Wedekind; +Cc: guile-user

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

Hello,

> Has anybody managed to get the "merge-generics" handler to work? I used to 
> have this in my $HOME/.guile configuration but it didn't seem to have any 
> effect:
> 
> (default-duplicate-binding-handler '(merge-generics replace warn-override-core
> warn last))

You need to import (oop goops), may be you do so in your .guile config file, I can't
tell from your email. Note that this 'only' would not solve the question raised by
the original email of this thread.

Anyway, it's not a good idea, imo, to put this in .guile, because not only you need
to have this properly set at load and compile, but your users too.

I suggest you read my 'just posted' answer to the original email of this thread, grab
and read the grip related example links I pasted and do take a special attention to
the last sentence as well.

David.

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

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

* Re: Modules and GOOPS
  2016-07-28 21:14 ` David Pirotte
@ 2016-07-29  5:17   ` David Pirotte
  2016-07-29 17:00   ` Kovacsics Róbert
  1 sibling, 0 replies; 11+ messages in thread
From: David Pirotte @ 2016-07-29  5:17 UTC (permalink / raw)
  To: Kovacsics Róbert; +Cc: guile-user

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

Re,

> ...

> This great global parameter setting, and API IMO, has been withdrawn in Guile-2.2,
> which hard codes duplicate handlers 'as in the manual'.

This above sentence is ambiguous/incomplete, here is more accurate 'version',
hopefully:

	This great global parameter setting, and API IMO, has been withdrawn in
	Guile-2.2. In 2.2, when a module does not declare its duplicate handlers
	set, using the #:duplicates module directive, then Guile 2.2 won't
	read the global parameter setting anymore, as it did in 2.0, it will assume
	instead that the user wants the default duplicate handlers set, as
	specified in the manual.

David.

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

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

* Re: Modules and GOOPS
  2016-07-28 21:14 ` David Pirotte
  2016-07-29  5:17   ` David Pirotte
@ 2016-07-29 17:00   ` Kovacsics Róbert
  2016-07-29 18:00     ` Marko Rauhamaa
  2016-07-31  2:35     ` David Pirotte
  1 sibling, 2 replies; 11+ messages in thread
From: Kovacsics Róbert @ 2016-07-29 17:00 UTC (permalink / raw)
  To: David Pirotte; +Cc: guile-user

First, thank you for your detailed answer!

On 28 July 2016 at 22:14, David Pirotte <david@altosw.be> wrote:
> First, generic functions are 'containers', that are not associated, and do not
> pertain to any class. <a> does not have a generic function x:

Thank you, I am still thinking in Java terms at the moment.

> Then unlike you've been told by others, I do not recommend to define generic
> function, they are just 'containers', the system creates them for you and it is an
> error [not implemented by Guile] to redefine a generic function. With the last in
> mind, manually defining GF will work if you play with a couple of your own modules,
> but it will almost certainly fail for large system.

 So what is the right approach when I'm implementing textbook data
structures (rather than want to use the given ones, for learning
reasons) and want to implement a set. On this set, I want to write a
method "closure" that computes all the elements of the set given a
function on the set elements, such that for any call to the function
with an element of the set, the result will also be in the set. This
is the same code for all implementation, but depends on implementation
specific code such as "contains?" and "add". Then I want to implement
different sets, e.g. red-black trees, AVL trees, etc.

The plan was something like this, but I think I may be trying to
achieve it wrong, or at least the unidiomatic way:

; <sets/set.scm>=
(define-module (sets set)
  #:use-module (oop goops)
  #:export (<set> add ... closure))

(define-class <set> ())

(define-generic add)
...

(define-method (closure (set <set>) (function <proceedure>))
  ... contains? ... add ... )

; <sets/red-black-tee-set.scm>=
(define-module (sets red-black-tree)
  #:use-module (oop goops)
  #:use-module (sets set)
  #:export (<red-black-tree>))

(define-class <red-black-tree> (<set>))

(define-method (add (tree <red-black-tree>))
  ...)

; <mbe/test.scm>=
... Code to exercise methods ...


> But if you do so, define generic functions manually, then I recommend do it in
> another module.

So I could move the add, etc, methods out into another module, if that
is the way to do it, but I need them, because without having them,
Guile will complain with "unbound variable: add". But this is a very
classes-contain-methods approach and given what you said, makes me
think that I'm doing this wrong thing.



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

* Re: Modules and GOOPS
  2016-07-29 17:00   ` Kovacsics Róbert
@ 2016-07-29 18:00     ` Marko Rauhamaa
  2016-07-31  3:59       ` David Pirotte
  2016-07-31 10:44       ` Chris Vine
  2016-07-31  2:35     ` David Pirotte
  1 sibling, 2 replies; 11+ messages in thread
From: Marko Rauhamaa @ 2016-07-29 18:00 UTC (permalink / raw)
  To: Kovacsics Róbert; +Cc: guile-user, David Pirotte

Kovacsics Róbert <kovirobi@gmail.com>:

> Thank you, I am still thinking in Java terms at the moment.
>
> [...]
>
> But this is a very classes-contain-methods approach and given what you
> said, makes me think that I'm doing this wrong thing.

I'm thinking GOOPS is the wrong thing here.

A better, more Schemey way is hiding in plain sight. Look at how ports
are created and manipulated. You have a rich set of methods that take
the best from Scheme and the classic object/method paradigm, eg:

   (with-output-to-string thunk)

   (with-input-from-file filename thunk)

   (port-filename port)

   (close-port port)


More generally, take a look at <URL:
http://www.delorie.com/gnu/docs/guile/guile-tut_10.html> and how
MAKE-CELL has been defined. That's true OOP without classes or slots.


Marko



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

* Re: Modules and GOOPS
  2016-07-29 17:00   ` Kovacsics Róbert
  2016-07-29 18:00     ` Marko Rauhamaa
@ 2016-07-31  2:35     ` David Pirotte
  1 sibling, 0 replies; 11+ messages in thread
From: David Pirotte @ 2016-07-31  2:35 UTC (permalink / raw)
  To: Kovacsics Róbert; +Cc: guile-user

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

Hello,

> First, thank you for your detailed answer!

Welcome

>  So what is the right approach when I'm implementing textbook data
> structures (rather than want to use the given ones, for learning
> reasons) and want to implement a set. On this set, I want to write a
> method "closure" that computes all the elements of the set given a
> ...

I won't have time to help you to design the all thing, but i can review
small and complete (no ...) code snipset. The code below is incomplete.

> ; <sets/set.scm>=
> (define-module (sets set)
>   #:use-module (oop goops)
>   #:export (<set> add ... closure))
> 
> (define-class <set> ())
> 
> (define-generic add)
> ...
> 
> (define-method (closure (set <set>) (function <proceedure>))
>   ... contains? ... add ... )

this is indeed not a very good design, imo: the fact that your <set> is an 'empty'
class, and with no applicable methods for the all the methods it calls in closure,
are the symptoms, imo, that this is not a good design

> ; <sets/red-black-tee-set.scm>=
> (define-module (sets red-black-tree)
>   #:use-module (oop goops)
>   #:use-module (sets set)
>   #:export (<red-black-tree>))
> 
> (define-class <red-black-tree> (<set>))
> 
> (define-method (add (tree <red-black-tree>))
>   ...)

I can only give an opinion, and it is only an opinion, if you provide full code
snipset: and your add method lacks an argument to add :)

> So I could move the add, etc, methods out into another module, if that
> is the way to do it

Nope, I did not say that, I did say that if you want to manually define generic
functions, then do it in a separate module, and imports that module when
necessary.

Although not strictly necessary technically speaking, we generally define methods in
the same module as the one where the class of its first argument (used to dispatch)
is defined. Just look at some of the clutter examples (links i previous email)...

> Guile will complain with "unbound variable: add". But this is a very
> classes-contain-methods approach and given what you said, makes me
> think that I'm doing this wrong thing.

The fact that you manually define the generic function "add" gives the 'illusion' the
design is good, but in fact, (add (make <set>) <element>) will fail with no
applicable method, which imo, is a sign that the¬this design is not good.

The fact that the GF definition is in the (sets set) module does not make the design
any better. If you persist in manually defining GF, do it in another module, that
all other module which needs them imports of course ...

David.






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

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

* Re: Modules and GOOPS
  2016-07-29 18:00     ` Marko Rauhamaa
@ 2016-07-31  3:59       ` David Pirotte
  2016-07-31 10:44       ` Chris Vine
  1 sibling, 0 replies; 11+ messages in thread
From: David Pirotte @ 2016-07-31  3:59 UTC (permalink / raw)
  To: Marko Rauhamaa; +Cc: guile-user

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

Hi Róbert,

> More generally, take a look at <URL:
> http://www.delorie.com/gnu/docs/guile/guile-tut_10.html> and how
> MAKE-CELL has been defined. That's true OOP without classes or slots.

IMO, this is exactly what you don't want.  You'll find some answers to why in the
following article, if you are interested:

		CLOS: Integrating Object-Oriented and Functional Programming
		Richard P. Gabriel Lucid, Inc.
		Jon L White Lucid, Inc.
		Daniel G. Bobrow Xerox PARC
		May 3, 2004

I also suggest you read the Stklos Object System (on which Goops is based),
online manual pages [1]: they are easier to read (then our Goops ref man) and have
some beginner examples (and some links (to a CLOS tutorial also): note that Sklos 
syntax is slightly different, but no big deal.

David.

[1]	http://www.stklos.net/Doc/html/stklos-ref-8.html#STklos-Object-System
	http://www.aiai.ed.ac.uk/~jeff/clos-guide.html

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

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

* Re: Modules and GOOPS
  2016-07-29 18:00     ` Marko Rauhamaa
  2016-07-31  3:59       ` David Pirotte
@ 2016-07-31 10:44       ` Chris Vine
  2016-07-31 16:38         ` Marko Rauhamaa
  1 sibling, 1 reply; 11+ messages in thread
From: Chris Vine @ 2016-07-31 10:44 UTC (permalink / raw)
  To: guile-user

On Fri, 29 Jul 2016 21:00:42 +0300
Marko Rauhamaa <marko@pacujo.net> wrote:
[snip]
> More generally, take a look at <URL:
> http://www.delorie.com/gnu/docs/guile/guile-tut_10.html> and how
> MAKE-CELL has been defined. That's true OOP without classes or slots.

For that simple kind of use you might as well use records.  R6RS
records are also inheritable, so you can construct type heirarchies;
SRFI-9 records are not.  Guile provides both.

Chris



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

* Re: Modules and GOOPS
  2016-07-31 10:44       ` Chris Vine
@ 2016-07-31 16:38         ` Marko Rauhamaa
  0 siblings, 0 replies; 11+ messages in thread
From: Marko Rauhamaa @ 2016-07-31 16:38 UTC (permalink / raw)
  To: Chris Vine; +Cc: guile-user

Chris Vine <chris@cvine.freeserve.co.uk>:

> On Fri, 29 Jul 2016 21:00:42 +0300
> Marko Rauhamaa <marko@pacujo.net> wrote:
> [snip]
>> More generally, take a look at <URL:
>> http://www.delorie.com/gnu/docs/guile/guile-tut_10.html> and how
>> MAKE-CELL has been defined. That's true OOP without classes or slots.
>
> For that simple kind of use you might as well use records.  R6RS
> records are also inheritable, so you can construct type heirarchies;
> SRFI-9 records are not.  Guile provides both.

The key is not to specify types (records or otherwise). Provide a
constructor plus opaque objects that have methods. As for the "simple
kind of use," there is no need for anything more complicated in
object-oriented programming.

How would the MAKE-CELL example above benefit from R6RS records?


Marko



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

end of thread, other threads:[~2016-07-31 16:38 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-27 17:53 Modules and GOOPS Kovacsics Róbert
2016-07-27 19:44 ` Jan Wedekind
2016-07-28 22:36   ` David Pirotte
2016-07-28 21:14 ` David Pirotte
2016-07-29  5:17   ` David Pirotte
2016-07-29 17:00   ` Kovacsics Róbert
2016-07-29 18:00     ` Marko Rauhamaa
2016-07-31  3:59       ` David Pirotte
2016-07-31 10:44       ` Chris Vine
2016-07-31 16:38         ` Marko Rauhamaa
2016-07-31  2:35     ` 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).