[plt-scheme] generics / modules

From: Yoav Goldberg (yoav.goldberg at gmail.com)
Date: Thu Oct 20 18:31:31 EDT 2005

Another code organization question, this time really not music specific.

I use multimethods / generics quite a bit in my code (I use my own
lightweight system, but the question applies to systems like
CLOS/swindle as well).

The problem I have is with the use of both generics and the module
system - where do I put the generic functions definition (which is the
actual function)?

In what I came up with there are "interface" modules, that contain
(almost) only generic function definitions. These are grouped by type,
for example I have the module
"interfaces/arithmetics.scm" which defines the generics
"add,sub,mul,div", as well as the comparison operators, and the min
and max functions. Then I have the "interfaces/values.scm" module,
which has a function named "get-value", and so on.

When I want to implement some or part of the interface, I create a
module that requires it, and adds methods to the functions defined in
the interface.
For example
(module pitch-arithmetics mzscheme
  (require "../interfaces/arithmetics.scm")
  (def-method add (pitch? interval?)
    (lambda (p i) ...)
   ...))
Note that this module does not provide anything.

When one want to actually do pitch arithmetics, he needs to require 
both "interfaces/arithmetics" and "pitch-arithmetics".

I am forced to do it this way, because if two modules implement the
same interface and I want to require both of them, I will have to
prefix one of them to avoid the name clash.. but I actually want the
name clash to happen, so I just don't provide anything.

So, my first problem is that multiple-require I'm forced to do.

My second problem is with generic functions that are not as widespread
or as easy to categorize as "arithmetics". For example, I implement
various "time" objects (time-point, time-interval, duration). And
there is a functionality which is required for all of them
(number-of-wholes <time>), and a recognizer (time? <time>) that should
work on all of them. Where do I put these two functions? Of course, I
create another interface module - "time-interface", which defines
them. And now, do I put this file under "interfaces/time-interface",
or under "time/time-interface"? Where is it more natural? Where will
it be most easily found? (remember, I can't just put it anywhere I
want and have the "time" module provide it - it needs to be
specifically required by the user, and he needs to find it.. I can
create another module, called "all-interfaces", and let someone
require only that, but I feel this is (a) wastefull (b) a mess. )

Ok, so that was my second problem - where to put these very little
interfaces that are used just once or twice anyhow.

Now for the third, which is an elaboration of the second. I had a
"number-of-wholes" generic function, defined in "time-interface". Now
there is another type, completely unrelated to time, that also needs
that "number-of-wholes" method. It is already defined in the
"time-interface". Will users of the other type need to include
"time-interface" in order to use the new type? I can't just add
another interface, because then I can't require both (conflicting
names), so I will have to change the place of the definition of
"number-of-wholes". This is problematic - I have quite a bit of code
that already require "time-interface" - this code will have to be
changed. Also, I have no idea where to put this "number-of-wholes"
definition now...


Did anyone else encounter similar problems? Are there any well known solutions?

Thanks,

Yoav


Posted on the users mailing list.