Contracts for Groovy

Tutorial – GContracts: A Design by Contract extension for Groovy

AndreSteingress

Andre Steingress introduces us to GContracts – an extension library for Groovy

Introducing GContracts

Bertrand Meyer, the creator of the Eiffel
programming language, introduced the concept of Design by Contract,
a technique for improving software robustness and reliability by
specifying formal contracts between class implementations.

In a way it is surprising that DbC never
found its way into the programming language main stream. At times
it has reportedly been under the top 25 requested issues of Sun’s
issue tracker for the Java programming
language
.

A contract is an agreement between a class
and its clients (classes using the class) and is a first-level
citizen of the programming language, standing on the same level as
program instructions and expressions.

To see how contracts can help improve
software reliability and robustness, we will start with the
Rocket class implementation (see Listing
1
). Before we jump right into specifying contracts, let’s
have a look at a technique that seems similar to DbC at first
sight: assertive programming. 

Listing 1

 

class Rocket  {
  int speed
  private boolean started
  
  def start() { started = true }
  boolean isStarted() { started }
  def accelerate()  { speed = speed + 5 }
  def brake() { speed = speed - 5 }
}

 

Assertive Programming

Programming is all about formalizing
internal thought models. Even with the finest requirement documents
and project methodologies, in the end internal thought models drive
the actual doing.

But with internal models come implicit
assumptions about the behaviour of certain things or software
elements. Assertive programming is about adding assertions to code
places where implicit assumptions need to be externalized and
proven.

Let’s have a look back at the Rocket
class. Once instantiated, a rocket object can be started,
accelerated and braked. The class has an internal state, resembling
its current speed, and a flag indicating whether the rocket has
been started or not. As you will see during the course of this
article, DbC especially fits domain classes in a sense of the
domain-driven
design (DDD) approach
, rather than record classes.

The Rocket class author implicitly
assumed that Rocket#brake() would never be called before
Rocket#accelerate(). But as implicit assumptions
should be embedded into the source code, we need to state this
assumption. In order to do so, one option is to use Groovy’s power
assertion statement: assert.

Listing 2

 

class Rocket  {
  int speed
  private boolean started

  def start() { started = true }
  boolean isStarted() { started }

  def accelerate()  { 
    assert started
    speed = speed + 5
  }

  def brake() { 
    assert started
    speed = speed - 5 
  }
}

 

If Rocket#brake() is now called before Rocket#accelerate(), an AssertionError is thrown and the following
message is shown:

 

Assertion failed: 
assert started
       |
       false

 

As can be seen from the code sample, the
assertion uses a Boolean expression to state its assumption that a
rocket must always be started prior to brake it. In Rocket#brake() and Rocket#accelerate() we can see the first
contract element: the precondition.

A precondition defines what must be true
in order to let the method succeed. In our case, the rocket
instance needs to be started, before Rocket#brake() or Rocket#accelerate() succeeds. It is the
Rocket client’s responsibility to start the
rocket instance. The stronger the precondition, the more work needs
to be done by the client. This precondition is the first part of
our Rocket class contract (as a side-note: a
contract itself has no representing source code element, it’s
simply an overlapping term for all conditions a class defines in
terms of its DbC elements, one of them being preconditions). We
will refer to a precondition as a contract
element
.

From assertions to contracts

As can be seen in Listing
2
, adding assertions quickly bloats code and makes the
actual business logic less readable. There is another not so
obvious catch: assertions are not compliant with two important
object-oriented principles, inheritance and polymorphism.

Just imagine if someone decided to create
a subclass of Rocket overriding the Rocket#accelerate() method by increasing only by
1. As a result, the implementation of Rocket#brake() would break as speed becomes
smaller than zero, being an invalid state for rocket objects
(see Listing 3). With assertions, there is nothing
a class author can do against overriding preconditions in
subclasses.

Listing 3

class AnotherRocket extends Rocket {
    def accelerate()  { 
        assert started
        speed = speed + 1
    }
}
    
def rockets = [new AnotherRocket(), new Rocket()]
def result = rockets.collect { Rocket rocket ->
    rocket.start()
    rocket.accelerate()
    rocket.brake()
    rocket.speed
}

println result // output: [-4, 0]

 

Another disadvantage is that a subclass
could easily erase the contract element defined by its parent class
via prohibiting the assertion statement leading to maybe unexpected
consequences.

It too violates the Liskov Substitution
Principle, as it would result in subclass instances that cannot be
replaced with parent class instances and vice versa, leading to
corrupt and unpredictable runtime behaviour. As can be seen in the
last code example, the Rocket instance behaves correctly when
methods are called in the collect closure, whereas the instance of
type AnotherRocket gets into an invalid object state. Just imagine
the code in the collect closure would be hidden under various
layers and indirections – without actually knowing the concrete
type, a client could never deduce an inappropriate object state
just by viewing the source code.

As we will see in the next section on
GContracts, there are even more advantages by applying DbC instead
of working with plain assertions:

  • Contract inheritance
  • Accessing old instance variable values in Boolean
    expressions
  • Getting the method’s return value in Boolean expressions
  • Adding class contracts to the generated documentation
  • Package- or class-level configuration of assertion enabled
    code

We can’t go into each of the enlisted
points in the rest of this article, just remember that DbC is more
than simply putting assertions into source code – it is fully
integrated in the object-oriented programming paradigm.

Design by Contract for Groovy

GContracts is an extension library
for the Groovy programming
language
. It supports Groovy versions starting from 1.8.0,
comes without any external dependencies and is released under a
BSD-styled license.

To include GContracts in a Maven or Ivy
based environment, you would simply include:

‘org.gcontracts:gcontracts-core:1.2.5′

 

Once GContracts jars are available in the
classpath, you just need to import the org.gcontracts.annotations.*
package to define class contracts. As soon as GContracts is
detected by the Groovy compiler, contracts will be automatically
added to the generated bytecode during the compilation process.

Contract Annotations

The package org.gcontracts.annotations.*
contains three annotations to be used for specifying contract
elements on Groovy classes:

  • @Requires for method preconditions
  • @Ensures for method postconditions
  • @Invariant for class invariants

Each annotation will use a language
construct that has been introduced in Groovy 1.8: closure
annotation parameters. Groovy supports closures as annotation
parameters by keeping Java byte-code compatibility. As closures are
compiled to inner classes, this is solved by adding a
java.lang.Class parameter to the annotation, so don’t get confused
when, looking at @Requires, @Ensures or @Invariant annotation
implementations, you can’t find a Closure attribute – it will be
resolved to java.lang.Class by the Groovy compiler.

To see how closure annotation parameters
look like, take a look at Listing 4. It shows the
imaginary annotation @Since which could be used to execute code
only within a specific version range. The actual code checking the
version number is specified within a closure annotation
parameter.

Listing 4

 

@Since( { version >= 1.0 } )

 

In this case, the closure annotation
parameter is the only annotation parameter. GContracts annotations
make heavy use of closure annotation parameters to define
contracts. So let’s start by exploring GContracts contract
annotations, starting with the precondition annotation @Requires.

  

Contract Element Part 1:
Preconditions with @Requires

@Requires is supposed to be used for
precondition specifications. It can only be applied on instance
method, static method and interface method declarations.
Listing 5 shows how our Rocket
class looks like after manually transforming all assertion
statements to preconditions.

 

import org.gcontracts.annotations.*

class Rocket  {

    int speed
    private boolean started
    
    @Requires()
    def start() { started = true }
    
    boolean isStarted() { started }
    
    @Requires({ started })
    def accelerate()  {
        speed = speed + 5
    }
    
    @Requires({ started })
    def brake() { 
        speed = speed - 5 
    }
}

 

As can be seen with respect to the
refactored Rocket class, the
introduction of @Requires for
preconditions leads to much cleaner code, as all assertion code is
moved to closure annotation parameters.

Code inside the closure annotation can
access method parameters, publicly accessible instance variables
and methods. If accelerate would come with a parameter dx indicating the speed delta, @Requires could be used to check for its
validity, too.

Listing 6

 

@Requires({ started && dx > 0 })
def accelerate(int dx)  {
    speed = speed + dx
}

 

The contract author is free to use
arbitrary Groovy language construct within the precondition, as
long as the resulting code is a Boolean expression. Otherwise,
GContracts will detect non-boolean expressions and will throw a
compile-time error.

As already noted, another major benefit of
using GContracts is its integration with inheritance and
polymorphism. If we would enhance the AnotherRocket subclass by overwriting
Rocket#accelerate() with a custom
implementation, we wouldn’t need to define the precondition again.
It would simply be inherited as AnotherRocket is a Rocket
descendant.

Listing 7

 

class AnotherRocket extends Rocket {
    def accelerate()  {  // @Requires will be inherited from Rocket
        speed = speed + 1
    }
}
    
def rocket = new AnotherRocket()
rocket.accelerate()

 

A call to AnotherRocket#accelerate() without a prior call
to AnotherRocket#start() would fail with a slightly
modified Groovy power assertion message:

 

org.gcontracts.PreconditionViolation: <org.gcontracts.annotations.Requires> Rocket.java.lang.Object accelerate()

 

started

|

false

 

 

The power assertion message shows the part
of the contract that has been violated, shows the results of
sub-expressions and points to the part of the Boolean expression
being “false”. This works even better with complex Boolean
expressions:

 

org.gcontracts.PreconditionViolation: <org.gcontracts.annotations.Requires> Rocket.java.lang.Object accelerate()

 

((1 + 1) * 3) == 7

    |    |    |

    2    6   false

 

 

 

In addition, GContracts supports
redefining base class preconditions. A precondition redefinition
can be achieved by providing an additional @Requires
annotation to AnotherRocket#accelerate() (see Listing
8)
.

Listing 8

 

class AnotherRocket extends Rocket {

    @Requires({ !started })
    def accelerate()  { 
        speed = speed + 1
    }
}

 

During compilation, GContracts will join
both preconditions to a single precondition. In order to still
support inheritance and polymorphism, preconditions can only be
weakened by subclasses, thus the precondition above would be equal
to @Requires({ started || !started
})
– an assertion always being “true”.

Contract Element Part 2:
Postconditions with @Ensures

So far, we did not talk about the general
concept of postconditions. As noted in the previous sections,
preconditions are a way to set certain boundaries for clients using
the class – postconditions invert that principle. A postcondition
states what in turn is guaranteed by the class author as long as
the precondition is satisfied.

GContracts provides @Ensures
for defining postconditions. The annotation can be applied on
instance method, static method and interface method declarations.
Back to the Rocket class example. Postconditions could be
added to Rocket#brake() and Rocket#accelerate(), to state that both methods
change the rockets speed in either way.

Listing 9

 

import org.gcontracts.annotations.*

class Rocket  {
    int speed
    private boolean started
    
    @Requires()
    def start() { started = true }
    
    boolean isStarted() { started }
    
    @Requires({ started })
    @Ensures({ speed - old.speed == 5 })
    def accelerate()  {
        speed = speed + 5
    }
    
    @Requires({ started })
    @Ensures({ old.speed - speed == 5 })
    def brake() { 
        speed = speed - 5 
    }
}

 

 

The postcondition code in Listing
9
shows another DbC-specific feature available solely for
postconditions: the old variable.

Inside @Ensures, a special variable named
old is available. It holds the values of all
typed instance variables of the current object. In our case, it
holds the speed instance variable, which is used to exactly
determine whether the speed has changed by 5.

There is a second variable available in
closure annotation code being used to refer to the actual method’s
result – assuming the method’s return type is not void – it is
called result. If accelerate would return the current
speed, we could refer the return value in @Ensures
(see Listing 10).

Listing 10

 

@Requires({ started })
@Ensures({ result - old.speed == 5 })
def accelerate()  {
  speed = speed + 5
  return speed

 

As it is the case with @Requires,
all postconditions are populated down the inheritance hierarchy and
multiple postconditions on a single method will automatically be
merged during the compilation process. In contrast to
preconditions, the merging rule for postconditions is such that
postconditions down the class hierarchy can only strengthen the
base class postcondition, never weaken it.

Contract Element Part 3: Class
Invariants with @Invariant

So far for our Rocket class … but wait.
What happens if we call Rocket#brake() multiple times without
ever calling Rocket#accelerate()? Right, the speed would turn
smaller than zero. But as it turns out, speed must
never be smaller than zero, being a formative property of
Rocket objects.

A property that has to be fulfilled
throughout the entire object life-time is called the class
invariant. Class invariants can be
specified with @Invariant. Again, the annotation uses a single
closure annotation parameter and again the contract element is
inherited to all direct and indirect subclasses.

Listing 11

 

@Invariant({ speed >= 0 && speed <= Integer.MAX_VALUE - 5 })
class Rocket  { ... } 

def rocket = new Rocket()
rocket.start()
rocket.accelerate()
rocket.brake()
rocket.brake() // fails with ClassInvariantViolation messsage

 

As you might have noticed, the
speed instance variable isn’t a real instance
variable, it is a plain-old Groovy object property. GContracts
automatically adds class invariant checks for all property accessor
methods, so calling rocket.speed = -1 would again result in
a class invariant violation.

Contracts, contracts,
everywhere …

GContracts becomes truly powerful when
using its annotations in library or framework base classes. As it
supports contract annotations on Groovy interfaces and abstract
classes, this is can be done straight-forward.

Let us introduce a RocketAPI
embedding the general contract directly in the interface
definition.

Listing 12

 

import org.gcontracts.annotations.*

interface RocketAPI {
  def start()
  boolean isStarted()
  int getSpeed()
    
  @Requires({ started })
  @Ensures({ result - old.speed == 5 })
  def accelerate()
    
  @Requires({ started })
  @Ensures({ old.speed - speed == 5 })
  def brake()  
}

@Invariant({ speed >= 0 && speed <= Integer.MAX_VALUE - 5 })
class Rocket implements RocketAPI  {

    int speed
    private boolean started
    
    def start() { started = true }
    boolean isStarted() { started }
    
    def accelerate()  {
        speed = speed + 5
        return speed
    }
    
    def brake() { 
        speed = speed - 5 
    }
}

def rocket = new Rocket()
rocket.accelerate()

 

As a result, all classes implementing the
RocketAPI interface must adhere to the specified contract. As said
earlier, preconditions can only be weakened, postconditions can
only be strengthened by implementation classes.

A call to Rocket#accelerate() without a preceding call to
Rocket#start() would now fail with the following
violation message:

 

org.gcontracts.PreconditionViolation: <org.gcontracts.annotations.Requires> RocketAPI.java.lang.Object accelerate() 

started
|
false

 

Notice that the error message’s originator
has changed to RocketAPI#accelerate(). As the contract elements
will be embedded in the resulting bytecode, we could put the
RocketAPI into a jar and every
project including the jar and GContracts would automatically be
forced to comply with the specified contract.

Conclusion

This article only showed a selection of
the most important core features of GContracts, with focus on the
core contract annotations: @Requires, @Ensures
and @Invariant.

More information on advanced features like
the custom Groovydoc Ant task for embedding contracts into
GroovyDoc generated class documentation, custom micro contract
annotations for reusing small but reoccurring contract elements and
disabling contracts on package- and class-level can be found at
GContracts project
wiki
.

To start playing with contracts, download
the most recent version (as of March 2012, 1.2.5) available on the
project homepage or

Maven central repository
, add it to the applications classpath,
import org.gcontracts.annotations
and your favourite programming language will magically support
Design by Contract.


Design by Contract™ is a registered trademark of Interactive
Software Engineering Inc
.

 

Author Bio: 

Andre Steingress works as
Groovy & Grails developer in Linz, Austria. He regularly blogs
at http://blog.andresteingress.com,
holds workshops and trainings focusing on Groovy, Grails and
Spring, enjoys contributing to the Groovy programming language and
is the creator of GContracts, a Design by Contract library for
Groovy.

This article originally appeared
in Java Tech Journal – The Groovy Universe. Check out the rest of
that issue here

 

Author
Comments
comments powered by Disqus