2

While I understand the value of implementation/interface distinction, I fail to see why most OO systems issue errors on access to private members.

I indeed wouldn't want to access private members in my main program.
But I would like to have that access for tests and debugging.

Is there any good reason whatsoever to issue errors and not warnings? The way I see it, I am forced to either write code I can test, but that doesn't utilize language support for interfaces, or use the language support, but have difficulty in testing.

EDIT

For those who suggested using public interfaces. You can, but it's less convinent.
On a conceptual level I find privacy that doesn't care about who or when quite crude.
Friend classes seem like a reasonable solutution. Another might be an 'all public' compiler switch.

Mechanical snail
  • 29,755
  • 14
  • 88
  • 113
sabof
  • 8,062
  • 4
  • 28
  • 52
  • 4
    The solution is to not write tests that directly access private members of the object under test. Your tests should operate on the public interface. – Oliver Charlesworth Jun 24 '12 at 00:33
  • 2
    By design, shouldn't private members have other (public) methods calling them already? The idea of private methods is to segment the internal workings of a class without complicating it's public interface. Why would you write a private method without a purpose (ie. a public method that calls it)? – Stecman Jun 24 '12 at 00:34

5 Answers5

1

The way I see it, I am forced to either write code I can test, but that doesn't utilize language support for interfaces, or use the language support, but have difficulty in testing.

Why do you need to access private variables and functions? Either they are called (however indirectly) by public functions at some point, or they are just inaccessible pieces of code that shouldn't be there at all because there is no way to invoke them. Think about it, if the private method is completely impossible to invoke from outside the class in any way at all, is it ever going to be run?

If you really want to test a private method anyway, you can pull it into its own class. Plus, if its so complex that it really needs to best tested individually, there's a chance that it deserves to have its a chance in the first place. The other option is to just make it public whenever you need/want to test it, but not actually change the 'real' code (leaving it private). As others have said, some languages also have features that help you test these methods by exposing them slightly more, such as friend in C++, internal in C#, and package-private in Java. Occasionally the IDE's themselves even help out.

Is there any good reason whatsoever to issue errors and not warnings?

One big reason is not so you can't call them, its so other people can't call them. Picture this, you're writing a library that's going to be used by a substantial number of clients. You've marked everything they shouldn't need to call private, and all the functionality they do need is public. Programmers go ahead and start using your library, write a bunch of code with it, and produce happy customers both out of themselves and their own clients.

A few months later, you decide to spice up your massively successful library, and find that you need to do a bit of refactoring. Hence, you [rename, add/remove a parameter from, delete] some of your private methods, but are careful to keep all of your public method's interfaces exactly the same to make upgrading a seamless process. BUT in this universe, compilers only issue warnings and not errors when you access a private variable, and several of your client programmers wrote code that calls those private methods. Now, when they try to upgrade to your new version of your library, they get a bunch of real errors because they can't call those private methods anymore. Now they either have to spend time finding out what went wrong with the code and rewrite potentially large parts of it that they don't remember anything about (did I mention that this is two years in the future?). Hence, they have to completely relearn how to use your library and rewrite their client code, which is far from fun for anybody. Now they're rather displeased that you were so inconsiderate as to literally break all of their code with your upgrade and make their lives far more difficult.

Guess what, when they were fixing the code, they researched and called your new private methods, so if you ever decide to change their interface when you issue an upgrade, the whole cycle starts over again. What was slightly more convenient for you just got you a bunch of unhappy customers.

Wait, weren't they idiots for calling my private methods? Why didn't they look at the warnings? This is their fault, not mine!

Well, yes, it is their fault and they could have prevented the problem by taking care to note those warnings. But not everybody is a code-quality fanatic who wants to fix and understand warnings, and a substantial amount of people just ignore them. The thing is, you could have prevented the whole thing yourself if compilers issued errors for trying to access private variables and methods instead of warnings, because otherwise the private keyword might as well not exist at all. You may have lost a little time because those methods are harder to test, but you have gained the power to keep less intelligent people from misusing your code and blaming you for any problems it causes them down the road.

One of my favorite tenets of software development (and product design in general) is that things should be easy to use correctly and hard or impossible to use incorrectly. True private members are the embodiment of this advice because they literally make your code impossible to use correctly.

[hypothetical retort:] Well, the people using my code should be smart enough to figure it out. All I'm asking them to due is just spend a little extra time to use the code correctly.

So you are consciously refusing to spend the time necessary to improve the quality of your code and make it easier to use? Then I don't want anything to do with what your code. Obviously your time is more important than that of your clients, so I'll take the 2.5 seconds it requires to close the web page for your project and click on the next Google result. There are a lot more private members of the libraries you use than you might think, and the glorious thing is that you don't have to spend even a millisecond of your time worrying about them because they're totally hidden from you and would only distract from the easier and better way of doing things that is provided in the public interface. If everything was public or wimpy-warning-issuing private, you'd have to sift through a greater amount of functions before you actually found what you wanted.

Whenever you type private before a member function, you have just given yourself the power to change it in any way you want at any point in the future because nobody can touch it but you. The second someone else tries to access it they will get a show-stopping error because the compiler has your back and won't let them do anything stupid with your code when you've already provided perfectly everything they need in a much more usable form in your public interface.

Yes, it will make it slightly harder to test in the now, but it has also ensured that you won't have to worry about it in the future when you refactor and made your code a lot easier for other people to use. Go ahead and make it public temporarily (I kind of like your 'all-public compiler switch idea :), but don't forget to switch it back when you're done you and your clients can all have the joy working with simpler and more adaptable code. :D

Community
  • 1
  • 1
Gordon Gustafson
  • 40,133
  • 25
  • 115
  • 157
  • Personally I believe that a user who doesn't have access to a 'risky' feature is equally likely to do 'the right thing' as he is to invent a new ingenious way to collapse the several buildings in the block while shooting himself the foot. My responsibility is to tell them which features are risky, but not enforce access. – sabof Jun 24 '12 at 02:56
  • What I don't like about strict encapsulation is that I don't get as many ways to explore my program. In languages that have good tools it might not be a problem. – sabof Jun 24 '12 at 03:01
  • @sabof He may have a good chance of getting it right anyway, but why not just take away his gun so he can't shoot himself in the foot in the first place? :) – Gordon Gustafson Jun 24 '12 at 12:06
  • What I mean is, the user might come up with a worse solution than accessing private/evaling/gotoing. Another aspect is that, I could do the 'wrong thing', see if it works, and then implement it properly or reject the idea altogether. A less flexible environment doesn't have as many bridges to different solutions. – sabof Jun 24 '12 at 13:43
  • Gosh golly gee willikers what a big answer, +1. – Camilo Martin Jun 25 '12 at 10:36
0

The obvious reason would be that all too many people seem to ignore many (all?) warnings. In some languages (e.g., Python) it's pretty much as you've said -- something being "private" is basically advice against outside code using it directly, but the compiler doesn't enforce that.

As for how much sense that makes, I suspect it varies between languages -- in something like C++, the attitude toward them ("protect against Murphy, not Machiavelli") could be seen as justification for its being a warning instead of an error.

I think it's safe to say that in Ada, that would receive a much cooler reception, to say the least (and that's not to say that I think it would be received warmly by C++ programmers either, just that they might not hate the idea quite as much as most Ada programmers would).

On the other hand, I have to wonder about the design of a class that can't be tested (at least reasonably well) via its external interface. On the rare (should be rare, anyway) occasion that you can't, I think making the test class a friend (in C++ parlance, though many others have similar concepts) would be fairly easy to justify.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I see how Ada programmers might not like the idea. Something along the lines of adjustable strictness might please everyone - dynamic development with static guarantees. – sabof Jun 24 '12 at 14:16
0

There are several advantages to having complete encapsulation:

  • Security. Strongly-typed OOP languages with strong encapsulation can have certain guarantees about the security of the data in the program. The Java language was designed with safety and security in mind, so certain library classes (for example, String or SecurityManager) cannot have their fields accessed. This prevents malicious code from doing Bad Things to these objects, and allows code to assume the objects are safe.

  • Maintainability. One of the major reasons to keep private fields and methods private is to allow the implementation to change seamlessly; as long as no updates are made to the public interface, code using the updated class can work with no changes. If you allow access to private fields and then change the implementation, you risk breaking an unbounded amount of code.

  • Stability/Verifiability/Testability. Classes typically impose invariants on their fields - for example, an implementation of a dynamic array might require that a field tracking how much space is used actually correspond to the total number of elements. Allowing people to arbitrarily access private fields, even with a warning, makes it possible to break these invariants. Without the ability to count on the invariants, it becomes difficult or impossible to reason about the correctness of the code. Additionally, if you do break an invariant somewhere in the code, you would conceivably have to look at every piece of code in the program that has access to the object, since any of them might be accessing the private field. With strong encapsulation, these invariants can't break, and with semiencapsulation through friends or package-private mechanisms, the amount of code to look at is bounded.

As for your question about testing - many languages allow encapsulation to be broken in certain cases; C++ has friend, Java has package-private, etc., so that the class can say "normally you can't touch these, but exceptions can be made." You can then make your testing code a friend or in the same package as the main class in order to test it more thoroughly.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 1
    I've never been convinced by an argument that encapsulation -> security (at least not in the OO sense). C++ has raw pointers, Java has reflection, etc. – Oliver Charlesworth Jun 24 '12 at 00:40
  • @OliCharlesworth- That is true, but C++ classes were not designed for security, while Java was. The security manager in Java is designed such that key classes can't be reflected into (for example, String, System, etc.), and it can be customized so that you can prevent access to key classes of your choice. I would say that it's not often used this way, but Java does provide this security. – templatetypedef Jun 24 '12 at 00:41
0

The way that I see it is that you need to forget about accessing anything in an object unless you have a way of doing that in that object's interface. I think a correct OO system ought to issue errors (and not warnings) if you are attempting to directly access implementation specific private members. I attended a good talk by Kevlin Henney on this subject recently and I found it very useful, a copy may be viewed here: http://www.infoq.com/presentations/It-Is-Possible-to-Do-OOP-in-Java (note that it is mainly about java but also includes comparisons to other OO systems)

For testing most time I find that most of the code under test is covered by public interface calls. It is only on rare occasions that I need to employ something like runtime reflection to get absolutely 100% coverage.

Barry
  • 635
  • 6
  • 7
0

I was about to post, "Strong enforcement of encapsulation keeps your boss from stepping on your private members." until I realized how that might sound wrong, but on second thought It's probably just about right.

starbolin
  • 840
  • 5
  • 13