Thursday, April 23, 2009

Java is NOT Design by Contract.

In a recent DZone comment thread somebody stated:
[...] Java did great in pushing design-by-contract [...]
This caught me off-guard; I've never heard anybody refer to Java as a DbC language before. The rationale provided was that Java was the first general-purpose language to push interfaces--but interfaces are probably the weakest form of DbC I can think of. (We'll ignore that Eiffel predates Java by something approaching a decade.)

Here's a simple example highlighting the weakness in thinking Java is DbC. A simple bank system might expose the following interface:

interface Account {
void deposit(Money amount);
void withdraw(Money amount);
Money getBalance();
}

We know the operations we can perform on an account, but know absolutely nothing about the behavior of an account or the expectations of the interface methods. Can the amount be null? Negative? We don't know. Does making a deposit actually increase the amount of money in the account? We don't know. Sure, we can check the Javadocs, but they're not tied directly to the code.

There is nothing contained in an interface definition other than the operations we can perform.

In Eiffel, a strong DbC language, the deposit() method would look something similar to the following. It turns out the Eiffel tutorial has this exact example, which I didn't know when I started. I've removed some of the example for clarity.

deposit (sum: INTEGER) is
require
non_negative: sum >= 0
do
balance := balance + sum
ensure
updated: balance = old balance + sum
end

Now we know, as does the compiler and runtime, that sum must be zero or above, as stated in the require section. We also know that when we're done that the new balance will equal the old balance plus what we just deposited, as defined in the ensure section.

Now that is DbC. But that isn't even all of it: Eiffel also allows class-level contractual information. The following is part of the tutorial's account class:

invariant
consistent_balance:
(all_deposits /= Void) implies (balance = all_deposits . total)
zero_if_no_deposits:
(all_deposits = Void) implies (balance = 0)

Still want to claim that Java is a DbC language? Yes, we can do all of this in Java code--but we can do that in any language, no matter how DbC (or not).

Interfaces may be *a* form of DbC, but they're the weakest form possible. Interfaces define only *what* we may do, and provide zero information about expectations.

In a previous post I discussed DbC for Java via SpringContracts; it's a step in making Java much more DbC-like. With a fuller expression language it would be a pretty good solution.

No comments: