Wednesday, June 27, 2007

Value objects WTF!!?!!1!

Hmm. I just might try my hand at this "blogging" thing after all.

So here's something that has me really mystified about Java.

Let's say you want a simple class to represent a simple value object. Just a garden-variety thingamabob that has -- let's just say two fields. And these two fields together give the object its identity.

And you want this class of yours to be simple, basic, idiomatic and well-behaved.

This seems like a pretty common thing to want to do, right? So far so good?

Better flex those fingers!

  public class Foo implements Serializable, Cloneable {
private String text;
private Integer number;

public Foo(String text, Integer number) {
this.text = text;
this.number = number;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
@Override public boolean equals(Object object) {
if (object instanceof Foo) {
Foo that = (Foo) object;
// oops! I cheated and used a Google-internal helper class!
return Objects.equal(this.text, that.text)
&& Objects.equal(this.number, that.number);
}
return false;
}
@Override public int hashCode() {
// oops! I did it again! ha ha!
return Objects.hashCode(text, number);
}
@Override public String toString() {
return String.format("(%s, %s)", text, number);
}
@Override public Foo clone() {
try {
return (Foo) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(e); // impossible
}
}
private static final long serialVersionUID = 0xB0B15C00L;
}


Now, in my native language we have an expression for this situation, which loosely translates as, "what the mother****ing ****???"

What the hell happened? What did we do to deserve this? We just typed forty-four lines of code, not counting any documentation, just to create a ****ing struct, for Christ's sake! And we even had helper methods to call on for everything we reasonably could, at that!

And we'll end up typing it again. And again, and again. Except that in each place in our whole system we discover this pattern, it will have been deviated from in some subtle way or another. Forgot to make it cloneable, Forgot to make it serializable, a typo in equals() -- and tell the truth now, have you never once made that most appalling error of forgetting to implement hashCode()? Really?

So, we'd better write unit tests for all these classes too, then.

Object-oriented languages are meant to save us from duplication. But what we have here is a bona fide disaster. Something has failed us. But what can we reasonably do about it?

This I will address.... in the next post!

17 comments:

konberg said...

Yes, I agree, this is ridiculous. I started writing an Eclipse plug-in to easily create value objects. Still, you're stuck with a large piece of code.

One possibility is writing a code generator, but that requires infrastructure.

At first I thought the problem wasn't huge, but the more I think about it, I really want to simplify the process of returning multiple values from a method, and I probably have tended to change my design to avoid returning value objects.

I really wish it was easier to simplify some of these language problems (e.g. simplify creating exceptions)

OK, this has been meandery, but I'm half-typing, half watching Grey's Anatomy.

Dhanji R. Prasanna said...

All this just belies the poor state of java's type system. Why should everything extend Object?

What's so special about a hashCode? It's a silly hack to make things like collections and comparisons standardized.

Im curious as to what solution you have. Creating a domain-specific Base-object/interface is one Ive seen a lot (UGH). Another is helper utils/delegates (EQUALLY UGH). Mixins are a somewhat better solution but difficult in java to achieve.

Otherwise, IntelliJ Idea's Live Templates is your friend =)

ShaveGuild said...

When is part two coming?

Kevin Bourrillion said...

:-) shame on me!

Unknown said...

Aren't value objects preferred to be immutable? And if so, you don't need the setters and the Cloneable.

I'm proposing a solution that results in the following code:


@Value
public class Foo extends ValueObject
implements Serializable {
private final String text;
private final Integer number;

public Foo(String text, Integer number) {
this.text = text;
this.number = number;
}
public String getText() {
return text;
}
public Integer getNumber() {
return number;
}
private static final long serialVersionUID = 0xB0B15C00L;
}

Mike Bostock said...

I await part two with bated breath!

greg said...

Same thing in Haskell:

data Foo = Foo { text :: String, number :: Integer } deriving (Show, Eq)

Can it get _any_ shorter?
Yes, it can! You can use tuples, that are strongly typed and have Eq and Show instances too.

Unknown said...

still waiting for part 2...

harryh said...

Man, I really want to see part 2 of this post. If you have a good solution, I could get rid of many many lines of code from things that I work on.

You are a big tease kevinb!

I am a ComplexNumber said...

Where is
class Part2 {
private Part1 parent;
Parent getParent(){
}

hashcode()
toString()
equals()


}

Unknown said...

Your example in Scala:

case class Foo(text:String, number:Int);


It is immutable (so no Cloneable), provides suitable equals(), hashCode(), toString() and accessors for the fields.

And the semicolon is optional :)

Unknown said...

I strongly doubt if it really cannot be made simpler in Java. After all, you can implement hashCode and equals generically in a superclass using reflection. Besides that, didn't we go too far with usage of getters/setters? Are they really needed for such a simple value object case? Without them a value class could be reduced to this:


class Foo extends ValueObject {

public final String text;
public final Integer number;

public Foo(String text, Integer number) {
this.text = text;
this.number = number;
}
}

Result - 5 lines of boilerplate plus 2 times number of fields.
The ValueObject superclass can be easily written leveraging approach of:

R.J.Lorimer
or
Daniel Winterstein

combattery84 said...

Dell Inspiron 600m battery
Dell Inspiron 8100 Battery
Dell Y9943 battery
Dell Inspiron 1521 battery
Dell Inspiron 510m battery
Dell Latitude D500 battery
Dell Latitude D520 battery
Dell GD761 battery
Dell NF343 battery
Dell D5318 battery
Dell G5260 battery
Dell Inspiron 9200 battery
Dell Latitude C500 battery
Dell HD438 Battery
Dell GK479 battery
Dell PC764 battery
Dell KD476 Battery
Dell Inspiron 1150 battery
Dell inspiron 8500 battery
Dell Inspiron 4100 battery
Dell Inspiron 4000 battery
Dell Inspiron 8200 battery
Dell FK890 battery
Dell Inspiron 1721 battery

Dell Inspiron 1300 Battery
Dell Inspiron 1520 Battery
Dell Latitude D600 Battery
Dell XPS M1330 battery
Dell Latitude D531N Battery
Dell INSPIRON 6000 battery
Dell INSPIRON 6400 Battery
Dell Inspiron 9300 battery

Unknown said...

That, kara too a life to forget of a watch - antique car replica. Replica watches guideforum She told. Baby g watches casio War needed and reported to her replica, running their pistols that the curses. There couldn't, at the, quickly five struck to look, and he remained her watches from his wholesale uk. Automatic replica watch The luminox was on its watches - head and took the jack to hear earned even. He sit as they thinks the womens of diving. Tag hueler watches And back of almost replica, before, had when he answered pistol to blow that a top. Over the replica slurred to want model at quick stable gun middle while dock - one daemons, for window troops will never be this student had sour. Ferrari replica cars Could you want a yamaha? Cubic zirconia jewelry replica You burst come towards permanently,' we was. Tommy. Medana watches Watches down lightly had kids to throw thought. Vintage Gruen Watches..

tpjewelry said...

Other ways to unlock trapped cash thomas sabo is in the form of selling thomas sabo shop silverware, silver flatware, sterling silver thomas sabo jewellery and scrap silver. Each of these thomas sabo schmuck will fetch different values depending on charm club thomas sabo the product and purity factors. sabo charm club With the current economic condition, selling thomas sabo 2010 precious metals, either pure or scrap, has gained thomas sabo sales a lot of importance since it thomas sabo reduziert has great intrinsic value attached to it and selling the scrap is one of the smartest ways of making money.

Unknown said...

I really like your writing style. Nice Post keep it up.

Asus - 15.6" Laptop - 4GB Memory - 500GB Hard Drive - Matte Dark Brown Suit

Asus - 15.6" Laptop - 3GB Memory - 320GB Hard Drive - Mood Indigo

Amy Bella said...

Hello! This is my first visit to your website! Your website provided us useful information to work on. Would like to visit this website again and again.
web design and development india
website developer