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
7.1.4 Experimenting with examples
Version: 4.2.1

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.

7.1.4 Experimenting with examples

All of the contracts and module in this chapter (excluding those just following) are written using the standard #lang syntax for describing modules. Thus, if you extract examples from this chapter in order to experiment with the behavior of the contract system, you would have to make multiple files.

To rectify this, PLT Scheme provides a special language, called scheme/load. The contents of such a module is other modules (and require statements), using the parenthesized syntax for a module. For example, to try the example earlier in this section, you would write:
  #lang scheme/load
  
  (module m scheme
    (define amount 150)
    (provide/contract [amount (and/c number? positive?)]))
  
  (module n scheme
    (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 argument to module should be the name of the module, so it can be used in a subsequent require statement (note that in the require, the name of the module must be prefixed with a quote). The second argument to module is the language (what would have come after #lang in the usual notation), and the remaining arguments are the body of the module. After all of the modules, there must a require to kick things off.