On Wed, 1 Dec 2010, Daniel Weinreb wrote:
Smalltalk didn't even try. CLOS, I believe, does not try and there is not an idiomatic way to do it. The only language I know that makes a good stab in this direction is C++, which has "public", "protected", and "private". Whatever else you say about C++, Bjarne understood this issue and tried to fix it. The C++ solution isn't perfect but it's sure a lot better than anything else.
If you like public, private, and protected, then you really need to study ADA a bit. CL isn't the only ~DARPA technology to have been abandoned even though it contained good ideas. All the constraints look like they could become tedious; but they seem to have good goals for defining interfaces. [No, I haven't done anything real in ADA.]
Secret on the C++ implementation: these keywords are only enforced at compile-time, and softly at best. On almost all compilers that matter, you can change them in the header files, completely violate the intended contract, and still link just fine with code compiled under the contract.
Java has a similar contractual model, but the JVM does try to enforce such boundaries at runtime.
All that said, I've started to believe that the approach is fundamentally wrong. There are always times when someone has to modify the "intrinsics" of a library. This is often needed to fix bugs, extend functionality in unanticipated directions, etc.
CL actually does have a decent way to do this, and a standard way to detect violations. Like C++, put each class in its own namespace (package). Only export symbols representing the public API. Everything else is part of the implementation/protected API. Violations of the public API the same way you find any other use of non-exported symbols.
Private is a good way of saying "are you really sure"; but the implementation is a misfeature. I suspect scary naming (a la the _underscore _prefix conventions commonly used in C/C++ and Python) are quite sufficient.
Later, Daniel
P.S. Other cute C++ tricks to get "private" data. These are strictly for debug/experimentation. Any sane coder would shoot you on sight for leaving them in a codebase.
- Protected data is easily accessed by creating a subclass and casting other pointers into it.
- LD_PRELOAD can be used to define :around methods on non-inlined functions, including methods. RTLD_NEXT can be helpful here.
- Calculate the offset of the value of interest, do a little pointer arithmetic, and cast.
- Reimplement a public member function in the same compilation unit (source file) as some code that needs to access private data. Simply copy the definition from the original source file; but add in hooks that expose private members (e.g. set globals pointing to them).