Note to readers (and refactorers): It has become apparent that this page is really more about the pros and cons of compiler- vs culture-enforced encapsulation, rather than encapsulation in and of itself.
In the CommonLispObjectSystem, for example, there is no (easy) way to enforce encapsulation, � la CeePlusPlus's private manner. So what happens instead is you have strong cultural norms which prevail: if a slot doesn't have an accessor or writer defined for it, you don't touch it. If a slot isn't documented to be for public consumption, you don't rely on it. If the accessor, even if it's there, is not exported from the package, you don't call it.
If you do any of the above, you're writing bad code, and will get no sympathy from the author.
Consequences
Makes refactoring and unit testing much easier for the implementor to just not have to worry about the public/private issue. No more "#define private public" in unit test harness code to get around the compiler.
"When I use a word, HumptyDumpty said, in a rather scornful tone, it means just what I choose it to mean, neither more nor less."
I don't think encapsulation is always a waste of time. The real goal of encapsulation is to minimize the interface presented to other parts of the program, which makes everything much easier to understand. But when a class has a bunch of attributes/properties/slots/fields/data-members/whatever-you-call-data-elements, defining get/set functions for all of them often is a waste of time, especially if the language doesn't provide a mechanism to enforce the encapsulation. -- KrisJohnson
Actually, in my experience encapsulation is far more valuable than inheritance or polymorphism. Encapsulation helps me write maintainable code that's tens of thousands of lines long. Since each class has a small group of public methods, you can consider one class implementation at the time when coding. You can refactor the class innards in isolation, as long as you don't break the public contract.
As with so many other code level issues, there are no simple rules for this. I really am rather tired of people insisting that you must always have get and set methods for everything as it is "good practice" without being able to give a coherent answer as to why.
Dogmatic application of patterns to every possible case can be worse than no patterns at all.
The actual argument this page is making seems to be CompilerEnforcementOfEncapsulationIsaWasteOfTime?. That makes it sound a lot like arguments about StaticTyping (not surprisingly: what's in an object's public interface is its type).
Furthermore, I think a lot of the reasons you don't need static typing when you're doing ExtremeProgramming are also reasons you don't need public/private/protected/friend/enemy/cheater when you're doing XP. If, for example, one part of your code (Class A) is reaching into the guts of another part of your code (Class B) and doing something intimate, you'll naturally refactor that code into Class B. And if you should change Class B before this, in a way that breaks Class A, that'll get caught by the tests.
Why, by the way, do we seem to so frequently confuse GoodWaysToProgram? with ThingsTheCompilerShouldForceUponUs? Is it because we reach first for a technical solution? Or because we don't trust anyone else to do the right thing unless forced to? Or what? -- GeorgePaci
ThingsTheCompilerShouldForceUponUs are really Rules Defined by the Implementor of a Class/Module for Users of that Thing. If the author of a class wants to make everything public, that's fine and the compiler will not force the author to do otherwise. But if the class writer wants to hide some aspects of the implementation, or wants to force users to use it a certain way, isn't it a good thing if the language provides a way to define (and enforce) those restrictions? I'll agree that in an environment where you have access to all the code and the right to change it all as necessary, encapsulation can get in the way. But in an environment where users of a class expect its public interface to not change, but the implementors want to be able to change the implementation if necessary, then encapsulation is a good thing. -- KrisJohnson
The actual argument this page is making seems to be CompilerEnforcementOfEncapsulationIsaWasteOfTime?.
Not so. The real underlying thrust of the argument is a dislike for BondageAndDisciplineLanguages, and highfalutin methodologists hijacking terms like what is and is not ObjectOriented. Some of us maintain that encapsulation may or may not be a desirable trait, but it certainly is not a defining feature of being ObjectOriented.
The CLOS idiom described above does exhibit encapsulation. It's just not enforced by the compiler. Instead, it's enforced using a combination of documentation, cultural forces, and self-discipline on the part of the client.
Clearly you believe that some objects have state that should not be accessed directly by the client. You state that such slots should only accessed through accessors, and that violating the accessor interface is bad code deserving no sympathy. The idiom that you've just described is, by definition, encapsulation. Apparently, you don't really believe that EncapsulationIsaWasteOfTime.
-- CurtisDuhn
I would add that the virtues of encapsulation depend on who the clients of your code are. We are currently working on making it easier for teams to share code. There are many teams, working for different business areas. The business areas don't necessarily have many interests in common. Cross-team cultural influence is pretty much zero.
I would say that in that situation any implementation detail exposed is an extra potential liability.
But if you're inside a team them you can obviously expose more because everyone can agree on what the ground rules are.
We package stuff on at least two levels - as C++ classes inside teams, and then via a strictly defined and documented API between teams.
Not too long ago, the glibc folks came out with a new version, which broke StarOffice. Why did this happen? The Star Office folks found some functions in glibc that they wanted to use, even though they weren't part of the explicitly exported API. They had been intended for internal use within glibc - so when the time came for that internal use to change, Star Office quit working with newer versions of the c libraries.
I think the lesson is that compiler enforcement can be a good thing for published libraries (imagine that you were a company publishing that C library - you'd have had to freeze and begin supporting those internal functions if the Star Office folks were a big enough client). OTOH, I work in perl and it's quite useful to reach in and frob an object's internals as part of a unit test... I just wish I could trust those BadProgrammers not to do the same in production code.
So, if it had not been possible for the Star Office folks to access these internal functions, what would they have had to do? I'm not familiar with the details of this case - were these `utility' functions that the StarOffice guys could have easily cut and pasted from glibc sources (OAOO notwithstanding), or were they accessors for, say, internal libc state that the application needed and couldn't get any other way?
I'm not arguing that it was OK for Star Office to do this - obviously, it wasn't. But sometimes I think it may be the lesser of two evils: if the choice is between delivering a system that uses implementation details, so works on today's computers but may break next year, and not delivering a system (until, maybe, next year) because there's no way at all to get to those implementation details, which would you choose?
Yeah yeah, I know. Straw Men R Us. But sometimes it's worth considering both sides of the argument. -- DanBarlow
I agree that this can be a case of YouArentGonnaNeedIt. The problem is, if you decide you aren't gonna need those get and set methods, you might have a lot of work ahead of you later when you found out you were wrong. I like the elegant properties solution in PythonLanguage (though I'd imagine that's not the first place it appeared). Just make data members for which you'd write get or set methods public. If it turns out later that you need to change the internal representation or something and need a get or set methods, you can at a property declaration to the class. The get/set/delete methods get called implicitly and none of the other code that uses the object needs to change. The result is more readable, you don't do encapsulation until you need it and you don't waste time. -- Anonymous
I like the approach taken in SmalltalkLanguage, where a member variable may be read by any object that wants to merely by referring to its name, but can only be modified by sending a message (and there might not be any such). This seems to prevent the problem that encapsulation is meant to address, objects promiscuously changing one another's state, without the overhead.