For some time, I’ve been trying to come up with better ways to explain the concept of design by contract. Rather than shooting for the best explanation, I figured I’d share a variety of explanations to appeal to a variety of folks. Today, we’re going to talk about design by contract in the context of boolean algebra, specifically implication. Let’s get to it!
Table of Contents
The Golden Rule of Design By Contract
If you’ve ever taken the time to tackle the concept of design by contract, you may learn that the entire premise can be boiled down to a single golden rule: if the precondition is true, then the postcondition can be assumed to be true.
The trouble with a statement like this is that it’s unclear what is expected to happen if the precondition is false. Taken in context, my students often assume that a false precondition means the code is guaranteed to crash. However, the reality is that we cannot assume anything will happen if the precondition is false. The code could crash, freeze, run forever, or even return a reasonable value. As a result, the only information we get from our golden rule is what is assumed to occur if the precondition is true.
Because I find this idea of uncertainty so difficult to convey to students, I thought I’d try my hand at explaining it through logic. Keep in mind that it has been ages since I’ve done any formal logic work, so my conceptual understanding could be off. But, these ideas really help me make sense of the golden rule.
Introducing the Idea of Implication
Whenever I first teach programming to someone, I really like to teach ideas related to boolean algebra. After all, those ideas translate almost directly into conditionals in programming. If you can grasp the ideas of AND, OR, and NOT, you have almost all of the tools you need to construct reasonable conditionals.
However, for most programmers, the ideas around boolean algebra usually stop there. Very rarely do we need to make use of ideas like NAND, NOR, and XOR (even if some of these are implied), and even more rarely do we need to know the various rules for simplifying and rewriting boolean expressions (e.g., De Morgan’s Law).
As a result, it’s no surprise that the ideas around implication are often not taught in programming courses. Ironically, implication plays really nicely into those concepts around conditionals. In fact, one way of thinking of implication is through the idea of if/then statements. If some statement (often called an antecedent) is true, then we expect the result (often called the consequence) to be true.
In design by contract, we take this idea of implication and make it our golden rule: if the precondition is true, then the postcondition can be assumed to be true. As a result, if this statement is not satisfied, we have failed design by contract. And this is shown through the truth table for implication:
Precondition | Postcondition | Pre -> Post (DbC) |
---|---|---|
T | T | T |
T | F | F |
F | T | T |
F | F | T |
Based on this table, design by contract is only violated if the client satisfies the precondition but the postcondition is false. Otherwise, the client is free to violate the precondition all day, and we guarantee nothing (i.e., the postcondition could be true or false, and design by contract would still be upheld).
Example Contract
To help make sense of this, here’s a method with a proper contract:
/** * Multiplies two numbers together. * * @param a the first term * @param b the second term * @requires Integer.MIN_VALUE <= a * b <= Integer.MAX_VALUE * @ensures product = a * b * @return the product of two integers */ public static int product(int a, int b) { return a * b; }
Under this contract, the user can provide any pair of integers as long as their product doesn’t exceed the maximum and minimum integers. Therefore, if the precondition is upheld, the user will get what they want. If for whatever reason, the user provides integers that exceed the range of int when combined, then we promise nothing. They could get the right answer or the wrong one. In this case, the product will wraparound, but we don’t guarantee that to the user.
At any rate, I doubt this will be the last time I talk about design by contract. Last year, I obsessed over recursion explanations, and it seems design by contract is the new focus. So, expect more of these types of discussions in the future.
In the meantime, why not check out my other discussions on design by contract (and recursion). It’s not a practice I use in my day-to-day life, but it’s a wonderful principle for thinking about the design of code:
- Improve Code Readability by Using Parameter Modes
- Maybe It’s Not Okay to Test Private Methods—at Least When Using Design by Contract
- The Official Recursion Cheat Sheet
- 5 Tips for Making Sense of Recursion
With that said, I’m going to wrap it up for today. Thanks again for your time, and I look forward to sharing more content with you soon!
Recent Posts
One of the core features of modern programming languages is functions, but did you know Python has them too? Let's take a look!
Python has a cool feature that allows you to overload the operators. Let's talk about what that means and how you might use it!