Sunday, September 12, 2004

More on domain objects

Several excellent comments and communications asked me questions about my post on domain objects. There are several points I want to discuss further.

Why implement boolean equals(Object), and why compare only primary keys?
This is a the heart of equality v identity or object equality v instance equality. The basic complaint is why not just rely on identity as implemented in boolean Object.equals(Object)? Why not, indeed. Do not forget that even if you override equals, you can just call == yourself which cannot be overriden (in Java) and which always provides identity, not equality. But for domain behavior you really do want things to compare equal which behave identically. In fact, without this property all sorts of code becomes very tedious. Just try to implement an object cache without overriding equals.
Why mark primary keys as final?
This follows from using equality instead of identity for equals. If a primary key changes, the object is no longer the same. The primary keys are therefore immutable. If you want a new domain object, you must create a new instance with different primary keys.

The Program

I want a domain-specific language (DSL) in Java for domain objects. Were I writing in a more modern, flexible language such as Scheme (just an example; there are others), I would simply design a DSL for the problem of domain objects. As it is, Java forces an amalgam of coding conventions and extra-linguistic baggage such as XDoclet (equivalently, JDK 5 annotations with code generation) or AOP to accomplish the same task. I want to consider here the Java-only techniques for this goal.

2 comments:

Emerson said...

Actually there is another very important semantic and logical reason for having an equals() method. Identity is always required, and at the very least you will need a compare() method which returns -,0,+ so that you can perform lexical compairson on objects. Lexical comparison lets you implement ordered collections and efficeint search algorithms.

Generally speaking equals() is redundant when you have compare() becuase compare() == 0 is the same as equals(). Or is it ?

Equality and comparison are in fact very different concepts, particulary from an optimisation perspective. When comparing two strings in english you must lexically examine the characters in each string from left to right to determine the correct result with respect to ordering.

If you are only interested in equality you can perform a much more efficent comparison by first checking that the lengths of the two strings are not different, and then perhaps if the strings you are comparing are URL's you might want to compare in reverse order since the end of the string is where the entropy will be greatest.

So from an implementation and performance perspective equals() is a necessary addition to any good API.

Brian Oxley said...

Emerson, your observations on equals v. compare are apropos, but your efficiency comment seems premature (to honor Knuth). In general, you should not try to figure out how an object external to you measures equality -- just call it's equals method and rely on that object to figure out for itself optimizations.