Sunday, June 11, 2006

Solving Method Contract Problems

In these last days an interesting discussion about the final Java keyword took place in many sites and blogs: take a look here and here.

I don't want to add my opinion about that because everything has been already discussed.
What caught my attention was the following statement in this very interesting blog post by Elliotte Rusty Harold:

It is a general principle of object oriented programming that an instance of the subclass can be used anywhere an instance of the superclass is expected. This is the very
definition of polymorphism. This means that the subclasses must maintain the class invariants and postconditions of their superclasses because client code might be depending
on those invariants and postconditions. Failure to do so is a contract violation. For example, if a Clock class promises that the getHours() method always returns a value
between 1 and 12, then this must still be true for a MilitaryClock subclass’s getHours() method. The MilitaryClock subclass can add a different getMilitaryHours() method that
returns a value between 0 and 23. However it must not violate the rule that getHours() always returns a number between 1 and 12.

I'm a huge fan of Design By Contract principles and agree with Elliotte in many points.
However, what I disagree with is how he solves the problem of maintaining the correct post-conditions on the getHours() method of Clock, that is, adding a getMilitaryHours() to MilitaryClock.

Why do I disagree?

Say you have a Display object for displaying time information through a Clock object, thanks to a displayTime(Clock c) method.
If Display.displayTime(Clock c) calls c.getHours() for obtaining the right hour time, it will not work with a 24 hours based MilitaryClock, because it will always display a 12 hours based Clock even if the actual Clock instance is a MilitaryClock!
Following Elliotte solution, Display should call getMilitaryHours(), but how?
Display doesn't know the actual type of Clock!
Moreover, adding a getMilitaryHours() method doesn't stop the client to use the standard getHours() method! Is this correct? Does the 12 hours based method make some sense for a MilitaryClock?

So, I see two solutions.

The first one: designing a Clock interface and two concrete implementations: StandardClock and MilitaryClock.
The Clock interface will have a getHours() method documenting the weaker applicable post-conditions, that is, an hour value between 0 and 23.
The StandardClock will strengthen the post-condition, outputting only values between 0 and 12.
The MilitaryClock will leave the post-condition as is.
This is safe and doesn't break any contract.
Elliotte could answer that interfaces are bad because don't let you verify conditions, forcing you to simply document them, and implementors to read your documentation.
I should write a whole blog post about this, but for now let me simply say that the value of interfaces is worth the price to pay. Surely.

The second solution: suppressing the getHours() method and implement a Clock.display() method, assigning to clock the responsability of displaying itself whatever time format it use, and let Display.displayTime(Clock c) call c.display().

Maybe Elliotte example was oversimplified, or his solution referred to a situation where you cannot change the base class (Clock), but simply saying that the solution to a "contract conditions problem" is adding another method, is IMHO a bit misleading.

My two euro cents.

What's your opinion about this?

Saturday, June 10, 2006

Spring Modules 0.4 released

The Spring Modules project has released today the 0.4 version: you can find the announcement here.

It is still under deep development and maybe not ready for certain production environments, but the modules I played with (or I read of) seem to be stable, and it contains a lot of interesting stuff.

In particular, I'm very interested in the Valang Validator, because writing Spring Validators in Java is often a very tedious and error-prone task: Valang is instead a simple, yet powerful, language for declaring validation rules and applying them to beans.

I think I'll write more about Valang in one of my next posts.

In the meantime, give it a try!