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, PLT Scheme supports contracts only 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
|
[amount positive?]) |
promises to all clients of the above module that 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 Scheme language, but if you wish to use scheme/base, you can explicitly require the contracts library like this:
(require scheme/contract) ; now we can write contracts |
|
[amount positive?]) |
7.1.1 A First Contract Violation
Suppose the creator of the module had written
|
[amount positive?]) |
|
(define amount 0) |
When this module is required, the monitoring system signals a violation of the contract and blames the module for breaking its promises.
7.1.2 A Subtle Contract Violation
Suppose we write this module
|
[amount positive?]) |
|
(define amount 'amount) |
In that case, the monitoring system applies positive? to a symbol, but positive? reports an error, because its domain is only numbers. To make the contract capture our intentions for all Scheme values, we can ensure that the value is both a number and is positive, combining the two contracts with and/c:
7.1.3 Imposing Obligations on a Module’s Clients
On occasion, a module may want to enter a contract with another module only if the other module abides by certain rules. In other words, the module isn’t just promising some services, it also demands the client to deliver something. This kind of thing happens when a module exports a function, an object, a class or other values that enable values to flow in both directions.