I have not been in a situation where a compiler error caused by these keywords would have saved me from a bug.
It's not so much to save application authors from bugs as to let library authors decide which parts of their implementation they're committing to maintaining.
If I have a library
class C {
public void foo() { ... }
private void fooHelper() { /* lots of complex code */ }
}
I may want to be able to replace foo
's implementation and possibly change fooHelper
in radical ways. If a bunch of people have decided to use fooHelper
despite all the warnings in my documentation then I may not be able to do that.
private
lets library authors break libraries into manageable sized methods (and private
helper classes) without the fear that they'll be forced to maintain those internal details for years.
What would make it worthwhile for the compiler to enforce information hiding?
On a side note, in Java private
is not enforced by the compiler, but by the Java bytecode verifier.
Can reflection override this mechanism? What would make it worthwhile for the compiler to enforce information hiding?
In Java, not only reflection can override this mechanism. There are two kinds of private
in Java. The kind of private
that prevents one outer class from accessing another outer class's private
members which is checked by the bytecode verifier, but also private
s that are used by an inner class via a package-private synthetic accessor method as in
public class C {
private int i = 42;
public class B {
public void incr() { ++i; }
}
}
Since class B
(really named C$B
) uses i
, the compiler creates a synthetic accessor method that allows B
to access C.i
in a way that gets past the bytecode verifier. Unfortunately, since ClassLoader
allows you to create a class from a byte[]
, it's fairly simple to get at the privates that C
has exposed to inner classes by creating a new class in C
's package which is possible if C
's jar has not been sealed.
Proper private
enforcement requires coordination between the classloaders, bytecode verifier, and the security policy which can prevent reflective access to privates.
Can it be used to secure a class' secret state from being attacked?
Yes. "Secure decomposition" is possible when programmers can collaborate while each preserving the security properties of their modules -- I don't have to trust the author of another code module not to violate the security properties of my module.
Object Capabilities languages like Joe-E use information hiding and other means to make secure decomposition possible:
Joe-E is a subset of the Java programming language designed to support secure programming according to object-capability discipline. Joe-E is intended to facilitate construction of secure systems, as well as to facilitate security reviews of systems built in Joe-E.
The paper linked from that page gives an example of how private
enforcement makes secure decomposition possible.
Providing secure encapsulation.
Figure 1. An append-only logging facility.
public final class Log {
private final StringBuilder content;
public Log() {
content = new StringBuilder();
}
public void write(String s) {
content.append(s);
}
}
Consider Fig. 1, which illustrates how one might build an append-only log facility.
Provided that the rest of the program is written in Joe-E,
a code reviewer can be confident that log entries can only
be added, and cannot be modified or removed. This review
is practical because it requires only inspection of the Log
class, and does not require review of any other code. Consequently, verifying this property requires only local reasoning about the logging code.