[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?



Posted on the users mailing list.