Friday, January 09, 2009

toString or not toString

suppose we have an Id class, which used as a 'pointer' to some persistent entities.

abstract class Id {
T _raw;
Id(T raw) { _raw = raw; }
@Overrride void toString() { return _raw.toString(); }

And the Object#toString() documentation says:
* Returns a string representation of the object. In general, the
* #toString method returns a string that
* "textually represents" this object. The result should
* be a concise but informative representation that is easy for a
* person to read.
* It is recommended that all subclasses override this method.
* The #toString method for class Object
* returns a string consisting of the name of the class of which the
* object is an instance, the at-sign character `@', and
* the unsigned hexadecimal representation of the hash code of the
* object. In other words, this method returns a string equal to the
* value of:
* getClass().getName() + '@' + Integer.toHexString(hashCode())

What is the problem?

* we heavily use these Ids in a *lot* of places
* id.toString() is used both for Id -> String conversion, as a part of our design and as textual representation for debugging/logging
* to subclasses AID and BID will have the same textual representation, making future debugging/logging more confusing then necessary
* if we enrich the Id with more data (eg. a timestamp, or entity version, etc.) we can no longer not add this extra data to its textual representation (eg. logging), since toString() is also used for conversion
** it is very hard to find all the usages of the toString method, since every IDE (and the compiler too) considers this method belonging to the Object and not to the abstraction Id (that's why the @Override is there)
*** if we would have worked in a TDD kind-of way, we probably would have started with an interface, IUniqueId, to which we probably would have added a method asString()

concluding advice: when you model your own domain language/design, be careful what you override.

No comments: