This is the mail archive of the guile@sourceware.cygnus.com mailing list for the Guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Trouble understanding define (!)


Neil Jerram <neil@ossau.uklinux.net> writes:

> When working with a generic, whose name might be the same as that of
> an imported generic, [...]

I would stop right here.  What does it mean for a generic to have a
name?  How is that different from a function having a name?  Or any
other object?

Suppose you have two modules that each define a constant named
"version".  Do you think the values for this constant should be
somehow combined into a single one when a third module imports both of
the former modules?  Maybe by computing the average when both
"versions" are numbers?

[ Uhh, I'm ranting, sorry.  This is not something personal.  I merely
  want you all to think about this. ]

Why should generics be handled any different from numbers?  It is not
clear to me that merging generics is a more useful operation than
taking the average of two numbers.  It might be a useful thing, once
in a while, but I don't want the module system to do it automatically.


I think it is instructive to compare the way Common Lisp gives names
to objects and how Scheme does this (or is supposed to do, as there
isn't any standard for module systems yet).

Common Lisp has the `package system'.  This is a mechanism that allows
one to control the read and print names of symbols, only.  Symbols can
in turn be used to name other objects.  CL has a number of independent
toplevel namespaces: one for variables, one for functions, one for
classes, one for slots, and so on.  Generic functions share a
namespace with ordinary functions and macros.

Scheme has only one toplevel namespace, which is a mapping from names
to bindings.  `Modules' will extend this to multiple toplevels, but it
should (IMO) continue to be a simple mapping from names to bindings,
indpenedent from the kind of object that is intended to be stored in a
certain binding.

That is, in Scheme, we can for example not use the module system to
manage slot names directly.  We can have nameless slot objects, that
are bound in toplevel namespaces and can thus be referred to by names.
But the question whether two slot objects are the same can not be
decided by comparing their _names_, we have to look whether they are
the same _object_, by using `eq?'.

The same thing applies to generic functions.  The name that has been
used to refer to the generic function itself is unimportant when you
want to add a method to it, for example.  All what matters is the
object that you get when using the module system to look up the
identifier, just like for any other kind of object.

I am not sure what kind of approach I like better, though I tend
towards the VL one, a bit.  It looks like it can deal better with
practical problems because one can introduce a new namespace very
easily and it is more oriented towards an interactive use of the
system.  The Scheme approach looks conceptually more beautiful to me
and I would like to explore it more fully.

For GOOPS slots, I think the most natural way would not be to have
`slot objects', but rather use the accessor functions to identify
slots.  This identification is important when performing slot merging,
for example.  I never really liked the concept of slot merging, too,
because it looks to me that it is too easy to merge slots
unintendedly, with strange consequences.  Not so bad as merging
generics, but still.

Slot accessors would be generic functions (maybe of a special kind to
allow for more agressive optimizations).  When declaring new slots
inside a class, each slot declaration would create a new generic
function and bind it to the given name.  It would be an error if a
binding for this name already exists.  Then a suitable method would be
added to this generic function that performs the slot access.
Alternatively, one could specify with an option that an existing
generic function should be used.  Then it would be an error if there
isn't a binding for the given name, or when it wouldn't contain a
generic function (but it does not need to be a generic function that
stems from a slot delclaration).

When slot merging is performed, those slots are collapsed into only
one slot that use the same generic function object as accessors.


This is not a very convenient approach, but it gives ample and
explicit control to the user.  Once we have clearly specified, clean,
and elegant semantics, we can think about how to make them a little
bit easier to use.  But not earlier.

Back to the example, where two modules export two unrelated protocols,
each consisting of a generic function that the modules want to export
under name "draw".  One is for drawing graphics, the other is for
drawing from a deck of cards.  A third module that imports both
protocols will get a name conflict unless it renames one or both these
bindings, maybe to "gfx:draw" and "deck:draw".  It has been argued
that both bindings could retain their original name, "draw", because
they both refer to generic functions, and because the methods they
carry supposedly specialize on unrelated types, they could be merged
into one generic function, without a conflict.  That way, one could
still use the short name.

I don't buy that this would be an improvement, even if it would be
possible.  The more I think about this, the more ugly I find it,
actually.  A module system is about managing names so that previously
unccordinated entities can be combined in a controlled way, without
fear of undetected name collision, and with the confidence that such
collisions can be handled once they occur.  It is not about being able
to use short, undescriptive names.  [Oops, sorry, I'm ranting again.]

It is not even clear to me that two generic functions can always be
combined automatically.  It is at best a operation with far reaching
consequences, and I don't want to the module system to do such
operations purely because two names are spelled the same.  I think
that overcoming the problems introduced by automatically combining
generic functions would force us to make a specific generic function
behave differently depending on what module contains the call to it.
We can't have that.  It would mean that Guile turns into an even more
unstructured mess of arbitrariness than it is now.

Suppose the "draw" function from the deck-of-cards module isn't really
a generic function.  What then?  It can't be silently turned into one.
I think it wrong to try to somehow `optimize' the behaviour of the
module system for generic functions.  Sometimes the `genericness' of a
function is part of the interface definition of a module, but
sometimes it is only an implementation detail.

Anyway, to finally come to a conclusion: I still don't think generic
functions should be handled any different by the module system.  Any
move to put special behaviour into the module system for certain kinds
of objects must be avoided.  The (imagined) loss of convenience is
not an argument at all.

- Marius

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]