Java generics and the “Smalltak setter” pattern

Anyone coming from a Smalltalk background recognizes the idea of setters returning “this”. (Smalltalk does it automatically). It can be useful when chaining multiple setters together. (See this) And it is more readable than having a method with several parameters. Which would you prefer?

1) Methods don’t return anything:

myObject.setValue1(value1);
myObject.setValue2(value2);
myObject.setValue3(value3);

2) One method with lots of parameters:
myObject.setValues(value1, value2, value3);
3) Setters return this:
myObject.setValue1(value1).setValue2(value2).setValue3(value3);

(1) requires the most typing and the most screen space, so it slows down good programmers.
(2) is the worst option because you (a) wind up with several combinations of all the setters (setValues12, setValues13, etc), and if value1, value2, and value3 are of the same class, then you risk putting the parameters in an incorrect order.
(3) Nothing wrong with (3). It is clear and readable.

Now there could be a style debate: Should we use the Java pojo style, i.e.,

myObject.setValue1(value1).setValue2(value2).setValue3(value3);

or should we go with Smalltalk style, i.e.,
myObject.value1(value1).value2(value2).value3(value3);

I could argue both povs, so I won’t argue at all.

—-
Now when you have a class hierarchy, you immediately run into a problem with this style. Look at the following code (I have placed all classes inside one outside class, so i can keep it organized. Ignore that issue as it doesn’t matter.)

public class TestThis {
static abstract class MySuperclass{
public MySuperclass setter1(String str1){
//set setter1
return this;
}
}
static abstract class MySubclass1 extends MySuperclass{
public MySubclass1 setter2(String str2){
//set setter2
return this;
}
}
static class MySubclass2 extends MySubclass1{
}
public static void main(String[] args) {
MySubclass2 mySubclass2 = new MySubclass2().setter1(“str1”).setter1(“str2”);//COMPILE ERROR
}
}

The problem here is that the setter1 method returns the MySuperclass type even though the instance is actually of type MySubclass2. Blame this problem on Java’s crappy strong typing model. use Scala if it bothers you too much.

Or use generics. Yes, the Java generics model is lame (See Scala if offended), but we can do it as follows (see this FAQ for the background)

public class TestThisGenerics {
static abstract class MySuperclass>{
public THIS setter1(String str1){
return (THIS) this;
}
}
static abstract class MySubclass1> extends MySuperclass{
public THIS setter2(String str2){
return (THIS) this;
}
}
static class MySubclass2 extends MySubclass1{
}
public static void main(String[] args) {
MySubclass2 mySubclass2 = new MySubclass2().setter1(“str1”).setter1(“str2”);//WORKS
}
}

Its tricky. You have to get that > just right. I don’t know about you, but I can’t quite understand it perfectly; I just do it.

There is one annoying thing in the above class. Do you see how we have to cast “this” with “(THIS)” every time. And the compiler warns us that this is an “Unchecked cast”, which it is. We know it is safe, but the compiler doesn’t.

I have learned the hard way that compiler generics warnings can really bite you. You are not always smart enough to ignore it. It does usually pay to remove them. This brings up the silly but necessary “getThis()” pattern (also see here), so here is the final code without any compiler warnings:

public class TestThisGenerics {
static abstract class MySuperclass>{
protected abstract THIS getThis();
public THIS setter1(String str1){
//set setter1
return getThis();
}
}
static abstract class MySubclass1> extends MySuperclass{
public THIS setter2(String str2){
//set setter2
return getThis();
}
}
static class MySubclass2 extends MySubclass1{
@Override
protected MySubclass2 getThis(){
return this;
}
}
public static void main(String[] args) {
MySubclass2 mySubclass2 = new MySubclass2().setter1(“str1”).setter1(“str2”);//WORKS
}
}


Leave a Reply

Your email address will not be published.