Cette page n'est pas disponible en français. Veuillez-nous en excuser.

ABIS Infor - 2012-06

OO programming: how private are your private parts?

Ludo Van den dries (ABIS) - 1 May 2012

Abstract

A surprising number of novice (or even experienced) programmers appear to misunderstand the meaning of access modifiers in mainstream OO languages such as Java, C++ and C#. Here are some reflections on public/private/protected visibility, encapsulation and the like.

How to get a free drink

It is an easy bet - I regularly try it when teaching ABIS courses on Object Orientation, OO Design, UML, Design Patterns, etc. Just launch the challenge: if you have two objects of the same class (e.g. two person objects john & mary, both instances of the Person class), can they 'see' each other's attributes and methods that have been declared with visibility private? The answer is yes of course, but nearly always, one or more students are prepared to bet on the contrary.

Eating the pudding

Indeed: in Java, C++ and C#, an object's private members can be accessed by any other object from the same class. Just in case you don't believe it, here is some sample code in Java.

public class Person {
	private String name;
	private String secret;

	public Person (String name, String secret){
		this.name=name;
		this.secret=secret;
	}

	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name=name;
	}

	public void ontfutselSecretFromPerson (Person p){
		System.out.println(p.secret);
	}
}

Now any client class could contain coding like this:

	...	
	Person mary = new Person("Mary","I like Brahms");
	Person john = new Person("John","I prefer strawberries");
	// or get hold of mary and john in any other way...
	...
	mary.ontfutselSecretFromPerson(john);

Of course this only works if mary gets a link (an object reference) to john, either passed as an argument (like in the above example) or through a permanent link, e.g. coming from an association 'is married/partnered to', which could be implemented as a (private) attribute partner:Person. In the latter case the client class could contain something like

	mary.ontfutselSecretFromYourPartner();

the client class would not have to pass john as an argument, and might not even know about john...

The above example is about private attributes, but of course the same holds true for private methods.

And what about encapsulation?

The unbelief of certain betters often stems from a misinterpretation of encapsulation, a cornerstone OO concept.

Encapsulation is sometimes explained in terms of data hiding: an object has data (state), organized in attributes, but it does not want other objects to access these data directly; instead other objects should act upon the object and its state in a controlled way through methods (behaviour): accessor methods (getters/setters (getFirstName()) or properties) or 'business' methods (calculateSalary()), and that's why the attributes are made private and the methods public.

That's only partly true. In fact, encapsulation is not about protecting an object and its data from other objects, but rather about protecting classes from other classes, and - also - about protecting the developer of a class from the developers of other classes: the less the others know about the inner workings of your class (the implementation), the more freedom you retain to modify the implementation of that class without telling the others, and without requiring modifications to the other classes. The others work with the public interface (everything required by the contract), while all implementation details are encapsulated inside the methods, and of course you - as a designer of your own class - are free to use the private members (private methods as well as attributes)...

Actually this boils down to that other architectural design principle: low coupling (achieve stability by controlling and reducing dependencies between classes).

Privacy is not secrecy

As illustrated, the mainstream OO languages do not prevent access between objects of the same class. Other OO languages may have more capabilities. E.g. I have been told that in Ruby the modifier private really means that only the object itself ('self') can use that member; if you want to allow access by other objects of the same class, you would use the modifier protected, which is different from the protected in Java and C# (there it means: visible by -- at least -- objects of the class and all its subclasses).

Similar object-level privacy seems also to be possible in e.g. SmallTalk (please contact a SmallTalk expert to know for sure...). But even in the case of Ruby and SmallTalk there are ways/workarounds (using reflection and all that stuff) so that one object can get to a private part of another object and access its content, so secrecy is not guaranteed.

In fact we could state that encapsulation and visibility offer compile-time protection (for managing change) rather than run-time protection (of object content).

Glad it works like that

Back to C# and Java now.

It is a good thing that objects of the same class have insight in each other's private structure. This feature is used intensively by the language itself, e.g. when comparing or cloning objects.

Two object variables o1 and o2 can be equal because they point to the same object (reference equality) or because their content is the same (value equality). The former equality can be tested in a generic way (they have the same OID (object identifier)), but the latter requires full knowledge of (and access to) the inner structure of the objects, maybe even some complex 'business logic' for deciding on the equality.

According to the Information Expert pattern (GRASP, Larman), the best place to put this responsibility of testing the value equality, is inside the class to which the objects belong, because that class knows all the details (even the most private ones). In practice, a class that wants to allow equality testing between its objects, will have to (a.o.) override the equals() method, so that the test could be done as follows:

	if (o1.equals(o2))... 

thereby using o1's read access to o2's private parts.

A similar story can be told about comparing two objects (e.g. for sorting collections):

	... o1.compareTo(o2)... 

returning values -1, 0, +1 for lessThan, equalTo and greaterThan

and about creating an identical copy of an object o1:

	... o2 = o1.clone()... 

where o1 now even uses write access to o2's private parts.

All of the above are just concrete applications of general OO design wisdom, masterfully laid down in standard works like the GoF Design Patterns book (1995 already...).

Conclusion

You may get pretty drunken by understanding OO principles.

You may get a pretty understanding of OO principles by attendig courses like
http://www.abis.be/html/en0767.html and http://www.abis.be/html/en0875.html.