7.1 Contracts and Boundaries

► |  | Guide: Racket

1 | Welcome to Racket
2 | Racket Essentials
3 | Built-In Datatypes
4 | Expressions and Definitions
5 | Programmer-Defined Datatypes
6 | Modules
7 | Contracts
8 | Input and Output
9 | Regular Expressions
10 | Exceptions and Control
11 | Iterations and Comprehensions
12 | Pattern Matching
13 | Classes and Objects
14 | Units (Components)
15 | Reflection and Dynamic Evaluation
16 | Macros
17 | Creating Languages
18 | Performance
19 | Running and Creating Executables
20 | Compilation and Configuration
21 | More Libraries
22 | Dialects of Racket and Scheme
| Bibliography
| Index

▼ | 7 | Contracts

7.1 | Contracts and Boundaries
7.2 | Simple Contracts on Functions
7.3 | Contracts on Functions in General
7.4 | Contracts on Structures
7.5 | Abstract Contracts using #: exists and #: ∃
7.6 | Additional Examples
7.7 | Gotchas

► | 7.1 | Contracts and Boundaries

7.1.1 | Contract Violations
7.1.2 | Experimenting with Contracts and Modules

On this page:

7.1.1`` Contract Violations
7.1.2`` Experimenting with Contracts and Modules

top← prev up next →

#### 7.1`` Contracts and Boundaries

Like a contract between two business partners, a software contract is an agreement between two parties. The agreement specifies obligations and guarantees for each “product” (or value) that is handed from one party to the other.

A contract thus establishes a boundary between the two parties. Whenever a value crosses this boundary, the contract monitoring system performs contract checks, making sure the partners abide by the established contract.

In this spirit, Racket encourages contracts mainly at module boundaries. Specifically, programmers may attach contracts to provide clauses and thus impose constraints and promises on the use of exported values. For example, the export specification

#lang racket
( provide/contract
[amount positive?])
( define amount ...)

promises to all clients of the above module that the value of amount will always be a positive number. The contract system monitors the module’s obligation carefully. Every time a client refers to amount, the monitor checks that the value of amount is indeed a positive number.

The contracts library is built into the Racket language, but if you wish to use racket/base, you can explicitly require the contracts library like this:

#lang racket/base
( require racket/contract) ; now we can write contracts
( provide/contract
[amount positive?])
( define amount ...)

##### 7.1.1`` Contract Violations

If we bind amount to a number that is not positive,

#lang racket
( provide/contract
[amount positive?])
( define amount 0)

then, when the module is required, the monitoring system signals a violation of the contract and blames the module for breaking its promises.

An even bigger mistake would be to bind amount to a non-number value:

#lang racket
( provide/contract
[amount positive?])
( define amount 'amount)

In this case, the monitoring system will apply positive? to a symbol, but positive? reports an error, because its domain is only numbers. To make the contract capture our intentions for all Racket values, we can ensure that the value is both a number and is positive, combining the two contracts with and/c:

( provide/contract
[amount ( and/c number? positive?)])

##### 7.1.2`` Experimenting with Contracts and Modules

All of the contracts and module in this chapter (excluding those just following) are written using the standard #lang syntax for describing modules. Since modules serve as the boundary between parties in a contract, examples involve multiple modules.

To experiment with multiple modules within a single module or within DrRacket’s definitions area, use the racket/load language. The contents of such a module can be other modules (and require statements), using the longhand parenthesized syntax for a module (see The module Form). For example, try the example earlier in this section as follows:

#lang racket/load
( module m racket
( provide/contract [amount ( and/c number? positive?)])
( define amount 150))
( module n racket
( require 'm)
(+ amount 10))
( require 'n)

Each of the modules and their contracts are wrapped in parentheses with the module keyword at the front. The first form after module is the name of the module to be used in a subsequent require statement (where each reference through a require prefixes the name with a quote). The second form after module is the language, and the remaining forms are the body of the module. After all of the modules, a require starts one of the modules plus anything that is requires.

top← prev up next →