On 1 Dec 2010, at 16:25, Daniel Weinreb wrote:
I call the set of defgenerics (plus the factory functions) the "protocol". The word "type" is sort of right but carries a lot of connotations and freight that I'd rather avoid.
In the Haskell community, these beasts are called 'type classes'.
How can we provide the same thing in Common Lisp? And without changing CLOS? In fact, without adding any new language feature at all?
Your suggestions to use packages for this kind of separation is good. There is another alternative that is actually already in use as well: In the CLOS MOP you have a distinction between user-level functions and extension functions. A typical example is the slot instance protocol which is specified like this:
(defun slot-value (object slot) (let ((slot-definition (find slot (class-slots (class-of object)) :key #'slot-definition-name))) (if slot-definition (slot-value-using-class class object slot-definition) (slot-missing class object slot))))
etc. for the other slot accessors. The important point for the sake of this discussion is that there is a user-level function slot-value that is supposed to be used as the front-end API, whereas slot-value-using-class exists for extensions of the CLOS functionality. Slot-value is actually a plain function, while slot-value-using-class is a generic function. I think this is a good way to organize your code and makes a clear distinction between user APIs and extension APIs. It may not work in all cases, but I think it's good to try this in your own projects. There is no real cost involved if the user-level functions can be inlined.
I admit that there's a significant problem, namely the same problem that we always have with packages. Because resolution of packages happens at runtime, it is difficult-to-impossible, in some cases, to change the package declarations during interactive debugging and have the effect that the environment behaves as if you had changed the package declaration and recompiled from scratch. All I can say is that we really ought to do something about the problems with packages, even if you don't buy anything I'm saying here.
A really strong point of packages is that they resolve symbols at read-time, while most module systems in the wild resolve identifiers at a later stage. This is a strong point because this means that packages can (a) make finer distinctions than module systems, and (b) can provide information hiding mechanisms (public vs. private symbols) completely orthogonal to whatever language constructs you may come up with. (a) is good because it's the main reason why macros are actually safe with regard to hygiene in all relevant practical cases, and (b) is good because you don't have to reinvent the wheel with regard to information hiding over and over again.
Any suggestions to change/improve packages should ensure that these strong points remain, IMHO.
Pascal