Anton,
These are all very good questions. I'm going to try to write up an essay about these topics suitable for posting on my blog, since there's so much to say.
The use of packages that I have been advocating here is not used a lot in practice in Common Lisp, but the more I think about it, the most I feel that it ought to be, or at least that it's worth a try. Using packages for shared libraries *is* used, very properly.
The use of packages for having more than one interface to a module, for separating the "call" interface from the "subclass" interface, and talking about getting away from the idea of using CLOS types as if they were CLU abstract types as far as modularity goes, have not been discussed much.
I don't know if I'm the first person to discuss this, or at least the first to address it from the point of view I'm writing from. If anybody knows of something I ought to be citing, please let me know.
I'll send mail to "pro" when I have something.
Thanks for providing encouragement for me to think about these things more deeply!
-- Dan
Anton Vodonosov wrote:
Daniel,
I think I understand the issue better now.
Not that your idea - how base class provides implementation for reuse by subclasses and using packages to specify this protocol - was impossible to understand from your first mail.
I see that my doubts and the form of my previous email are caused by the fact that I still don't completely understand OOP and classes, despite I use it for years and spent some efforts on understanding it.
I understand how the program will be behave when I use this or that language feature; I have partially understanding and partially "feeling" about what is right, know common patterns how OOP is applied in different situations. But still I don't have a mental model which clearly defines all the concepts and fits them together: classes, protocols, modularity... how these concepts overlap? what does it mean to "implement a class"?.. what belongs to a class and what does not, and so on.
BTW, I've been constantly thinking for maybe 3 days and made several steps further in clarifying my mental model (although open questions remain).
I am taking back my words that public and protected are single protocol - I understand the nature of this separation better now.
Minor clarification of the previous mail:
Taking you literally, we do not need a new CL feature. But translating what you're saying into the terms I am using, you're saying that we need only one protocol, whereas I am saying that it's better to have two.
Actually I meant that even for Java it could be better to have only package public and package private, as Common Lisp has; without public/private/protected for classes. In your example with the Point class, getX, getY would be package public, and the data members x and y would be package private (and at any time may be changed to an angle and a distance from the origin, without breaking the clients). Maybe in Java it will cause some inconvenience: e.g. with single inheritance in some situations reusing implementation may require lot of typing if we want to delegate method implementations to an "implementation utility" class from other package: void m() {implForReuse.m();}. But Java is not the subject here, so we may leave it aside.
The "print" and "to_string" example is illustrative; although the people who relied on the fact that the "print" uses "to_string" were relying on an undocumented feature; it's their own bug, not the library vendor's. Therefore IMHO the Ada 95 solution is not obligatory, I agree that people should expect only documented behaviour to be preserved in future versions. But of course, reducing the number of such undocumented entry points into the implementation may help them to avoid such bugs.
The ParaSail link is really interesting. BTW, I suppose the idea to plug-in programmer defined static checks into compiler is not intrinsically contradicting with the Common Lisp - maybe it's possible to implement something in this fashion for Lisp too (with certain limitations, but useful in practice). I've been thinking a little about that before (if we can introduce new language constructs expanded at compile time, why can't we implement compile time checks); and it's interesting to see somebody actually implements it for a language.
To not loose the point of this thread, as I said the idea to use packages to specify protocol for subclasses seems right. It's necessary to try it in practice.
Best regards,
- Anton