views:

613

answers:

12

A co-worker of mine is taking an Introduction to Object Oriented Programming class and was asked a discussion question by his professor:

Why are many developers opposed to using the "protected" modifer on/within classes?

When the question was brought up at lunch, my co-workers and I couldn't think of reasons why someone might be opposed to using the protected modifier on a class. Setting the premise of the question aside (which assumes that many developers are in fact opposed to the protected modifier; are they?), we tried to figure out why.

Personally, the only times that I've used the protected access modifier on a class is when I've written code that I might want to supplement in a test environment. For example, I might write a base class with no debugging information and then create a new class for testing, inheriting from the base class and overwriting its methods to add in debug output code before/after the base method calls. I suppose I could just as easily use a design that involves interfaces and dependency injection to accomplish the same goal, but my only experience with protected has been for testing purposes. In this case, the only reason to avoid protected is because you can accomplish the same thing in better ways.

Why might developers be opposed to using the protected modifier in their OOP design?

NOTE: Because the professor is asking a general OOP question not specific to any one language, I'm not sure if answers might be weighted differently because of different implementations of protected in C#, Java, etc..

+3  A: 

Encapsulation is considered a good practice, and by making members protected, you break the encapsulation because subclasses can modify the variable directly.

Ikke
possible typo: did you mean "break the encapsulation" (not "take") ?
timday
He didn't say it was for variables. The same arguments would apply to public.
DJClayworth
You do realize that many virtual functions may be marked as 'protected', right? That does not break any rules of encapsulation.
Ed Swangren
+3  A: 

Without extensive polling, I'm just taking a guess here, talking mostly about the protected modifier as applied to member functions.

I suspect it's because protected: on class members explicitly allows future users to modify the class behavior. Generally speaking this is hard to plan for. The problem lies in how many unknowns you have to both deal with and document for.

If your library allows subclasses to override protected methods, you have to be careful that every call of a protected method is somewhere that is safe for a programmer who is not familiar with particular requirements of the library. This requires careful documentation, and there currently isn't a good way of restricting usage in the popular languages.

As an example, assume you have a reasonably complete interface library that provides a CImage class. Your screen-raster mechanism 'locks' this CImage class during drawing. But your CImage class provides a protected "getPixel()" function. A user of your library overrode that function for their own use elsewhere, and tried to lock the image. This kind of issue is very important to communicate in documentation, and is simply a pain in the neck to handle for every protected member function or bit of functionality.

jkerian
+1  A: 

Personally I almost never use protected fields. It can be dangerous and a simple accessor will avoid any unwanted change.

With protected fields/methods, your subclass depends on your parent class internal structure which is really bad for coupling. It's a way to say "I have a 'private' method/field, but it's okay for my subclasses to use it", and worse "it's okay to override/modify it".

This is not really my opinion but I can understand that some developers find the protected modifier ugly to use.


Resources :

Colin Hebert
+9  A: 

Developers don't complain about protections until they prevent the developer from getting to something they want to use. For developers that are creating child classes, protected is no big deal because they'll have access to the goods from within their child classes.

For developers that are using a given class (not extending it), protected blocks access to potentially juicy internal implementation details. This is what they will gripe about.

It can be said that some framework designers error too much on the side of privacy - deny access to everything and only allow access to specific documented, supported features. This can be frustrating when you know there's good stuff on the inside that you could use to solve your immediate problem, but consider the flip side: if your framework were instead designed by someone who gave free access to everything, all the internal details of the implementation, you will very likely encounter one of two things when the framework is updated at some point in the future:

  1. The updated framework changes implementation details that your code is dependent upon, and your code breaks
  2. The designers realize they can't change the implementation without breaking lots of code, so they opt to not implement useful features or bug fixes. This is called code paralysis.

Even though it's frustrating to see things you can't access, it's better for code longevity and lower revision costs to operate in a restrictive (deny all, permit by exception) mode than in a permissive mode.

I have worked on (nay, written) frameworks in which developers using the framework complained about it not being permissive enough with internal details. These folks complained even as bugs were fixed, features were added and the implementation was rewritten across various platform migrations, but the public, supported interface, the contract of the code remained stable and their code remained largely unaffected.

So, in a nutshell, developers will complain about protected (and private) access modifiers simply because it gets in the way of what the developer feels would be the simplest and fastest way to implement a solution, ignoring the future cost of relying on such implementation details.

Encapsulation is a good thing, even when it blocks the shortest path to solution. ;>

dthorpe
@dthorpe I think I missed reading this the first time, but your comment that the public supported interface serves as a "contract of the code" seams to really drive home why access modifiers are so important in design. Great answer.
Ben McCormack
+1  A: 

protected members result in your class having two interfaces: one for clients that choose not to subclass, and a bigger one for clients that choose to subclass. protected classes are kind of the same - they're adjuncts to your public class that presumably do something, but they only do it for certain clients.

Occasionally that really is what you want to do: you've designed both interfaces carefully, for two different use-cases. Abstract classes might fall into this category: you have "implementers" using the protected+public interface, and "users" using only the public interface. There might be some useful functionality which you can provide to implementers that users don't need, and there might be configuration stuff that users don't touch, but implementers have to set up. Doing this with protected methods just saves you from defining a separate interface for some factory to return to the "users". So I don't think it's harmful, although it might be considered a bit quirky since it's not the "normal" way to define two interfaces.

The thing to be sure of, though, when you use protected, is that you aren't in fact breaking encapsulation in a situation where the code you want to break it for just so happens to be a subclass. If something "should" be private, then making it protected is breaking the encapsulation that you originally intended. A bad interface is still a bad interface, regardless of whether it's presented to the world or just to subclasses. For that matter, chances are that any pleb off the street can subclass your class. So even "just to subclasses" isn't very restrictive - your bad protected interface isn't far from public. I think that's why people are by default suspicious of protected - it looks as though it sweeps badness under the carpet by restricting who sees it, but really it doesn't.

the only reason to avoid protected is because you can accomplish the same thing in better ways.

Isn't that enough? Doing things better is... better ;-)

Steve Jessop
@Steve I read the sentence you quoted and thought, "that sounds like something I've said." Then I re-read my question and saw that it was in fact something I had said :-). Thanks for your answer.
Ben McCormack
+3  A: 

because object interaction is superior to inheritance.

James Gosling reportedly said that should he do Java over again he'd do without classes, and clarified that by "classes" he meant inheritance. protected is meaningless (or reduces to private) without inheritance (although not in Java), but with inheritance, it explodes into a slimy public degenerate, and more so in Java (http://programming-scala.labs.oreilly.com/ch05.html, "Protected Visibility").

Allen Holub writes (in Holub on Patterns which is a Java book, but great from a general OOP perspective) that protected is public by another name, especially in Java where . a protected symbol is one that can't be trusted to be what you see within the class it's declared in. other classes (descendants) can swap it under your nose. you're dealing with the yo-yo effect.

Gosling and Holub hint at the notion that interaction among objects is superior to class inheritance. there might be a little more of it, but that code will be better in terms of the software quality metrics (more flexible, easier to adapt and extend to new requirements) than code based on inheritance-based code. of course you need to be pragmatic. Holub writes that inheritance (protected) has its place in production code, but as a code volume-optimization, not a design element. in fact, all design should be done in terms of interfaces, which means public-only.

just somebody
Do you have a link for that James Gosling comment?
WW
just somebody
@WW: found something better after all: http://www.artima.com/intv/gosling34.html and http://www.artima.com/intv/gosling13.html (via http://zoomblab.blogspot.com/2009/11/james-gosling-must-be-loving-go.html). actually, Artima's not only a Holub-independent source, it shows Gosling has alluded to inheritance-free OO languages on multiple occasions.
just somebody
A: 

In java, the protected modifier often makes no sense.

If you are developing a single-package application and you do not anticipate it will be extended (it is not a library), then it would be better to use the default modifier - package private.

If you are developing a multi-package application, then you may need the protected modifier to allow beta.Son to invoke the alpha.Father superclass constructor (but otherwise the alpha.Father constructor is unavailable). I will speculate without proof that developers prefer single-package applications.

If you are developing a library, then the protected modifier would be useful. I will speculate without proof that developers spend more time building applications than libraries.

emory
+2  A: 

First, protected is no guarantee of privacy, unless the only consumable class in your inheritance chain is sealed (i.e. all base classes are internal to the assembly). Any developer who knows ANYTHING about OOP can derive your class and expose all your internals to the world.

Using internal on members instead usually solves this problem; only YOUR code, located in the same assembly you're developing, can see an internal member. The public children you expose for the use of others can be derived from outside the assembly, but the internals you want hidden are still hidden. Developers creating children or other objects in the same assembly should be communicating with you as to what they're using, if your internals really are that sensitive from a runtime perspective. Remember that protected internal means protected OR internal, not protected AND internal.

Second, protected generally indicates some flaw in class design, especially if both protected and public are used. If you have a secret, but you have to share it with your children, it's not much of a secret and it should probably be public. If it's REALLY a secret, your children shouldn't be trusted with it, because unless you give your kids a vasectomy with the sealed keyword, you can't stop them from telling THEIR children, who may no longer think it's much of a secret and share it with their household or the world.

Using protected is not terrible, it just does not accomplish what many developers want to use it for; to make a class's innards accessible to "trusted" individuals without risking exposure of delicate internal processes. It's less access control and more access suggestion; by using protected, you are stating that this method is useful for children, but that by itself it doesn't do much good to non-children, or would be harmful to the class if exposed and misused. That's pretty much like posting a sign in your front yard that says "My door is locked, and I'm not going to give you the key, but all my kids have one". That's not even the half of it, because a "burglar" can MAKE one of your kids and use them to unlock the door.

A common and well-accepted use of protected on methods is for Template Method classes; these are abstract classes that have a public skeletal workflow, but allow or require extension of specific pieces of their functionality to be useful. These pieces of functionality are generally highly cohesive and minor. The pattern would expose a public, non-virtual "driving function", and several handles to "helpers" as protected abstract or virtual methods. This allows consumers to derive the class and implement the helpers.

In that case, you usually don't care about the child implementation, and don't want to restrict the possible solutions; children may need public wrappers for the helper methods in order to communicate with THEIR dependencies.

protected is also the most straightforward way to unit-test the innards of a class. Unit testing is a good thing, but if you want to write a test fixture that exercises a method, that method must be accessible from outside the class. Private is simply a no-go. Internal usually presents a similar problem. To allow innard testing at all, they have to be at least protected, so that you can derive the class FOR THE EXPRESS PURPOSE of exposing the innards. Otherwise you need some really oogly reflection to extract a MethodInfo of your private method and invoke it (along with SkipVerification CAS permissions).

KeithS
@KeithS: Would not "Protected" be useful for abilities which are supported by the base class, but may not be supported in all derived classes? Derived classes that wish to support and expose the abilities may do so (and compel all classes derived from them to do likewise) while those that don't want to support those abilities can decide not to expose them (and--if desired--forbid any derived classes from doing so).
supercat
Protected deals with visibility and thus with use, not with the ability to override. AFAIK it is impossible to compel or forbid exposing a protected member through a child; if the child can see the member, they can create a public method that calls the protected method, but can never be forced to. You can compel a child class to IMPLEMENT a method with a particular signature using abstract, and forbid same via sealed. However, the child class must implement the overriding method with the same visibility, as it is part of the signature of the method being overridden.
KeithS
+1  A: 

One reason for "Protected" is that it may be useful for a class to include in its contract things which are true of the class but need not be true of derived classes. Under the Liskov Substitution Principle, anything that can be done via public interfaces with an object of type Q should also be doable with any object whose type inherits Q. Thus, Q should not advertise any ability which may not be present under some derivatives of Q.

On the other hand, suppose that Q has some ability which would be useful in some derivatives but not others, such as cloning. The base type Q can be cloned, provided certain conditions are met, but some subtypes might not support cloning. In that case, Q should expose as "Protected" the hooks needed to support cloning. Subtypes that could be usefully cloned could use those hooks and expose a cloning method. Those which cannot be cloned would not expose the hooks.

A sealed class which derives from the base type (which supports cloning only using protected methods) can be certain that any objects of its type will support cloning. Even if the class is not sealed, unless someone improperly derives from it a class which cannot support cloning, the code in the derived class can be certain it will only be used with objects that can be cloned.

By contrast, an class which does something with a passed-in object of the base type would have no compile-time way of knowing whether the objects it's given will be ones that support cloning or not. Exposing the lower-level cloning methods would invite them to be called in situations where they aren't supported.

supercat
+2  A: 

Overuse of protected could potentially lead to violation of Liskov Substitution Principle (L in SOLID) - PDF link. The principle states that classes should be written in a way that any subclass can be substituted for its base class. Robert C. Martin has a good discussion about that in Agile Principles, Patterns, and Practices in C#. The crux of the argument is that a subtype is only a subtype when it's substitutable for its base class, not simply having IS-A relationship.

So, by exposing too much functionality through protected methods, you could possibly allow the subclass to relax the invariants too much and make the subclass not a true subtype.

This is far from being black and white and one could not issue a blanket rule stating whether or not protected should/shouldn't be used. There are cases where it's genuinely necessary and there are cases where it's not. Using judgement in individual case is required.

Igor Zevaka
A: 

There's a rule.."Use Private unless you have a good reason not to" You have to think if someone gonna use your packages/classes and decide what is really needed. I never use protected unless I'm going to release a lib to someone else and only if it's needed.

Alex
+1  A: 

Because protected is public to its subclasses, it's kind of API to subclasses. It looks like many public methods to client.

卢声远 Shengyuan Lu