Book chapter published: Confined Roles and Decapsulation in Object Teams — Contradiction or Synergy?
I strongly believe that for perfect modularity, encapsulation in plain Java is both too weak and too strong. This is the fundamental assumption behind a book chapter that has just been published by Springer.
- The book is:
- Aliasing in Object-Oriented Programming. Types, Analysis and Verification
- My chapter is:
- Confined Roles and Decapsulation in Object Teams — Contradiction or Synergy?
The concepts in this chapter relate back to the academic part of my career, but all of my more pragmatic tasks since those days indicate that we are still very far away from optimal modularity, and both mistakes are found in real world software: to permit access too openly and to restrict access too strictly. More often than not, it’s the same software exhibiting both mistakes at once.
For the reader unfamiliar with the notions of alias control etc., let me borrow from the introduction of the book:
Aliasing, by the way, is one of the reasons, why analysis for @Nullable fields is a thorny issue. If alias control could be applied to @Nullable fields in Java, much better static analysis would be possible.
How is encapsulation in Java too weak?
This manifests at two levels:
Member access across instances
In a previous post I mentioned that the strongest encapsulation in Java – using the private modifier – doesn’t help to protect a person’s wallet against access from any other person. This is a legacy from the pre-object-oriented days of structured programming. In terms of encapsulation, a Java class is a module utterly unaware of the concept of instantiation. This defect is even more frustrating as better precedents (think of Eiffel) have been set before the inception of Java.
A type system that is aware of instances, not just classes, is a prerequisite for any kind of alias control.
Object access meets polymorphism
Assume you declare a class as private because you want to keep a particular thing absolutely local to the current module. Does such a declaration provide sufficient protection? No. That private class may just extend another – public – class or implement a public interface. By using polymorphism (an invisible type widening suffices) an instance of the private class can still be passed around in the entire program – by its public super type. As you can see, applying private at the class level, doesn’t make any objects private, only this particular class is. Since every class extends at least
Object there is no way to confine an object to a given module; by widening all objects are always visible to all parts of the program. Put dynamic binding of method calls into the mix, and all kinds of “interesting” effects can be “achieved” on an object, whose class is “secured” by the private keyword.
The type system of OT/J supports instance-based protection.
Java’s deficiencies outlined above are overcome in OT/J by two major concepts:
- Dependent types
- Any role class is a property of the enclosing team instance. The type system allows reasoning about how a role is owned by this enclosing team instance. (read the spec: 1.2.2)
- Confined roles
- The possible leak by widening can be prevented by sub-classing a predefined role class
Confinedwhich does not extend
Object. (read the spec: 7.2)
For details of the type system, why it is suitable for mending the given problems, and why it doesn’t hurt in day-to-day programming, I have to refer you to the book chapter.
How is encapsulation in Java too strict?
If you are a developer with a protective attitude towards “your” code, you will make a lot of things private. Good for you, you’ve created (relatively) well encapsulated software.
But when someone else is trying to make use of “your” code (re-use) in a slightly unanticipated setting (calling for unanticipated adaptations), guess what: s/he’ll curse you for your protective attitude.
Have you ever tried to re-use an existing class and failed, because some **** detail was private and there was simply no way to access or override that particular piece? When you’ve been in this situation before, you’ll know there are basically 2 answers:
- Give up, simply don’t use that (overly?) protective class and recode the thing (which more often than not causes a ripple effect: want to copy one method, end up copying 5 or more classes). Object-orientation is strong on re-use, heh?
- Use brute force and don’t tell anybody (tools that come in handy are: binary editing the class file, or calling Method.setAccessible(true)). I’m not quite sure why I keep thinking of Core Wars as I write this 🙂 .
OT/J opens doors for negotiation, rather than arms race & battle
The Object Teams solution rests on two pillars:
- Give a name to the act of disregarding an encapsulation boundary: decapsulation. Provide the technical means to punch tiny little holes into the armor of a class / an object. Make this explicit so you can talk and reason about the extent of decapsulation. (read the spec: 2.1.2(c))
- Separate technical possibility from questions of what is / should / shouln’t be allowed. Don’t let technology dictate rules but make it possible to formulate and enforce such rules on top of the existing technology.
Knowing that this topic is controversial I leave at this for now (a previous discussion in this field can be found here).
Putting it all together
- If you want to protect your objects, do so using concepts that are stronger than Java’s “private”.
- Using decapsulation where needed fosters effective re-use without the need for “speculative API”, i.e., making things public “just in case”.
- Dependent types and confined roles are a pragmatic entry into the realm of programs that can be statically analysed, and strong guarantees be given by such analysis.
- Don’t let technology dictate the rules, we need to put the relevant stakeholders back into focus: Module providers, application developers and end users have different views. Technology should just empower each of them to get their job done, and facilitate transparency and analyzability where desired.
Some of this may be surprising, some may sound like a purely academic exercise, but I’m convinced that the above ingredients as supported in OT/J support the development of complex modular systems, with an unprecedented low effective coupling.
FYI, here’re the section headings of my chapter:
- Many Faces of Modularity
- Confined Roles
- Safe Polymorphism
- From Confined Types to Confined Roles
- Adding Basic Flexibility to Confined Roles
- Non-hierarchical Structures
- Role Playing
- Translation Polymorphism
- Separate Worlds, Yet Connected
- Layered Designs
- Improving Encapsulation by Means of Decapsulation
- Zero Reference Roles
- Connecting Architecture Levels
- Instances and Dynamism
- Practical Experience
- Initial Comparative Study
- Application in Tool Smithing
- Related Work
- Nesting, Virtual Classes, Dependent Types
- Multi-dimensional Separation of Concerns
- Modules for Alias Control