0

I'm trying to implement my own programming language, and i'm currently doing lexing and parsing. I'm nearly done and want to add native support for class invariants, preconditions and postconditions.

public withdraw (d64 amount) : this {

    require amount > 0;
    require this.balance - amount > this.overdraft;

    # method code

    d64 newBalance = this.balance - amount;
    ensure this.balance == newBalance;
} 

You would also be able to define class invariance at the top of the class.

class BankAccount {
    invariant this.balance > this.overdraft;
    # class body
}

These are my questions:

  1. Would it make sense to include class invariance in abstract classes, or interfaces.
  2. Would it make sense to include preconditions in abstract methods and interface methods.
  3. Would it make sense to include postconditions in abstract methods, or interface methods.

Thinking about it myself, i don't think it makes sense to include invariance or postconditions in interfaces, but i don't really see a problem with preconditions.

It would be possible to include pre- and postconditions in abstract and interface methods like below.

public interface BankAccount {
    public withdraw (d64 amount) : this {

        require amount > 0;
        require this.balance - amount > this.overdraft;

        # no other statements (implementation)

        d64 newBalance = this.balance - amount;
        ensure this.balance == newBalance;
    }
}
Thomas
  • 537
  • 1
  • 4
  • 14
  • Why would preconditions be ok but not postconditions? – Lee Feb 26 '17 at 16:17
  • @Lee Since if there is no implementation in interfaces, what would you use to check in postconditions? In the above example you don't really know whether a `this.balance` exists. – Thomas Feb 26 '17 at 16:19
  • Invariants just relate to members so if interfaces can have properties then you could declare an invariant about them. Interface methods can have postconditions just like any other method. – Lee Feb 26 '17 at 16:44
  • @Lee thank you for your answer – Thomas Feb 26 '17 at 16:52

1 Answers1

0

It really depends on whether your interface is stateful or stateless. It can be perfectly fine to include pre and/or post conditions for interface methods. In fact, we do this all the time. Any time you create a piece of javadoc (or any other tool), you are creating a contract. Otherwise, how could you test anything? It's important to realize that test-driven-development and design-by-contract have much in common. Defining a contract is essential to proper tdd - you first design an interface and create an informal contract for it (using human-readable language). Then, you write a test to ensure contract is satisfied. If we follow tdd classicists (https://www.thoughtworks.com/insights/blog/mockists-are-dead-long-live-classicists), we always write tests against contracts.

Now, to be more specific. If interface is stateful, we can easily express its invariants according to other methods. Let's take a java List interface as an example:

If you read the javadoc carefully, you will see there are a lot of invariants. For instance, the add method has the following contract:

  1. Preconditions: element cannot be null (if list doesn't support it - it's a design smell btw in my opinion, but let's set it aside for now)

  2. Postconditions: ordering is preserved, i.e. the ordering of other elements cannot be changed

Since List interface is definitely stateful, we can reason about the state of the list using query method, like get, sublist etc. Therefore, you can express all the invariants based on interface's methods.

In case of an interface which is stateless, such as Calculator, we also define a contract, but its invariants do not include any state. So, for example, the sum method can have the following contract:

int sum(int a, int b)
Preconditions: a and b are integers (which is automatically guaranteed by static type checking in Java)
Postconditions: the result is an integer (again - type safety) which is equal to a + b

Our Calculator is a stateless interface, therefore we don't include any state in our invariants.

Now, let's get back to your BankAccount example:

The way you describe it, BankAccount is definitely a stateful interface. In fact, it's a model example of what we call an Entity (in terms of domain-driven-design). Therefore, BankAccount has it's lifecycle, it's state and can (and will) change during its lifetime. Therefore, it's perfectly fine to express your contracts based on the state methods of your class. All you need to do, is to move your amount, balance and overdraft to the top of the interface, either as properties (if your language supports it) or methods - it doesn't really matter. What's important is that amount, balance and overdraft are now part of your interface, and form the ubiquitous language of your interface. These methods/properties are integral part of your entire BankAccount interface - which means, they can be used as part of your interface's contract.

Some time ago I've implemented a very simple prototype of Java contracts, implemented as set of annotations supported by Aspect Oriented Programming. I tried to achieve similar goal to yours - to integrate contracts with language and make them more formal. It was just a very simple prototype, but I think it expressed the idea quite well. If you are interested - I should probably upload it to the github soon (I've been using bitbucket for most of the time so far).

Mike Wojtyna
  • 751
  • 5
  • 10