TNBT – Object Teams

15. March, 2011

Object Teams, or OT/J for short, is a solution for the old Java problem “there is no I in ‘team'”: Most Java code is written as if the whole world was openly hostile. It’s riddled with final, private static, singletons, thousands of lines of code which almost do what you need except for this one line .. that you can’t change without copying the other 999.

Groovy’s solution: AST transformation. A topic for another post.

OT’s solution: create a Java-like programming language which allows you to extend code that isn’t meant to. A great example: Extending Eclipse’s Java compiler.

The Eclipse Java compiler is one of the most complex pieces of code in Eclipse (“5 Mbytes of source spread over 323 classes in 13 packages“). Unlike other compilers, it can compile broken code. The same technology is used to create byte code and error markers in the editor.

Stephan Herrmann wanted to add support for @NonNull and @Nullable. Usually, you’d create a branch, keep that branch in sync with the main branch, etc. Tedious. For every change that someone makes in the main branch, you must update your development branch. Even if the change is completely unrelated. CVS has a very limited concept of “related”. DVCS like Git or Mercurial are better at merging but they also don’t understand enough of Java to give the word “related” a useful meaning. “Same file” is the best you can get.

So instead of the tedious way, he used OT/J to create an OT/Equinox plug-in which patches the JDT compiler byte code. Sounds dangerous? Well, OT/J does all the ugly work. You just say “when this method is called, do this, too.” Sounds a bit like AOP? Yes.

Unlike AOP, it communicates intent more clearly. The code wasn’t designed to be the most compact way to define a “point cut” and then leave it to the reader to understand what this is supposed to mean. It better communicates the intent.

I’m not completely happy with the syntax, though. I don’t have specific points, only a general wariness. Maybe a careful application of Xtext would help.

Related Articles:

  • The Next Best Thing – Series in my blog where I dream about the future of software development

When inheritance is not enough

16. September, 2010

Ever had the problem that inheritance just wasn’t enough? For example in this case:

package core;
public class Main {
    public static void main(String[] args) {
        sayHello();
    }
    private static void sayHello() {
        System.out.println("Hello World!");
    }
}

Say you need to override sayHello(). What are your options?

You could edit the source. But if you only have the bytecode?

You could decompile the bytecode. But what if you need the same change in several places?

Eventually, you’ll have to use copy more or less code around because Java just doesn’t offer enough ways to combine code. The solution? Object Teams. See this article for a solution of the problem above.

What is Object Teams?

In a nutshell, a team is a group of players which have roles. Usually, the roles are distributed by way of the strengths of your players. Slow and sturdy ones will be defense. Quick and agile players will attack. The calm ones will do tactics.

OT/J (the Java implementation of Object Teams) does just that: You define teams and roles and then apply those to existing Java code. Let’s take the Observer pattern (you know that design patterns are workarounds for flaws in the language’s design, yes?).

The problem with this pattern is that you can’t apply it retroactively. You must modify the involved classes to support the pattern even if they couldn’t care less. That leads to a lot of problems. Classes which don’t need it must still allocate resources for it. It clutters the API. You can’t add it to classes which don’t support it. If a class only allows you to observe some behavior, you can’t change that.

OT/J fixes all that. The OTExample Observer shows three classes which could make use of the Observer pattern but don’t. Instead, the pattern is retrofitted in all the places where it’s necessary. This allows for many optimizations. For example, you can create a single store for all your observers (instead of one per instance). The API isn’t cluttered. You can observe almost any change.