1 Welcome to PLT Scheme
2 Scheme 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 Performance
18 Running and Creating Executables
19 Compilation and Configuration
20 More Libraries
Bibliography
Index
On this page:
7.1.1 A First Contract Violation
7.1.2 A Subtle Contract Violation
7.1.3 Imposing Obligations on a Module’s Clients
Version: 4.0.2

 

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

  #lang scheme

  

  (provide/contract

    [amount positive?])

  (define amount ...)

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:

  #lang scheme/base

  (require scheme/contract) ; now we can write contracts

  

  (provide/contract

    [amount positive?])

  (define amount ...)

7.1.1 A First Contract Violation

Suppose the creator of the module had written

  #lang scheme

  

  (provide/contract

    [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

  #lang scheme

  

  (provide/contract

    [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:

  (provide/contract

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

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.