8 Contracts🔗ℹ

+Contracts in The Racket Guide introduces contracts.

The contract system guards one part of a program from another. Programmers specify the behavior of a module’s exports via (provide (contract-out ....)) or (require (contract-in ...)), and the contract system enforces those constraints.

The bindings documented in this section are provided by the racket/contract and racket libraries, but not racket/base.

Contracts come in two forms: those constructed by the various operations listed in this section of the manual, and various ordinary Racket values that double as contracts, including
  • symbols, booleans, keywords, and null, which are treated as contracts that recognize themselves, using eq?,

  • strings, byte strings, characters, +nan.0, and +nan.f, which are treated as contracts that recognize themselves using equal?,

  • numbers (except +nan.0 and +nan.f), which are treated as contracts that recognize themselves using =,

  • regular expressions, which are treated as contracts that recognize byte strings and strings that match the regular expression, and

  • predicates: any procedure of arity 1 is treated as a predicate. During contract checking, it is applied to the values that appear and should return #f to indicate that the contract failed, and anything else to indicate it passed.

Contract combinators are functions such as -> and listof that take contracts and produce other contracts.

Contracts in Racket are subdivided into three different categories:
  • Flat contracts can be fully checked immediately for a given value. These kinds of contracts are essentially predicate functions. Using flat-contract-predicate, you can extract the predicate from an arbitrary flat contract; some flat contracts can be applied like functions, in which case they accept a single argument and return #t or #f to indicate if the given value would be accepted by the contract. All of the flat contracts returned by functions in this library can be used directly as predicates, but ordinary Racket values that double as flat contracts (e.g., numbers or symbols) cannot.

    The function flat-contract? recognizes a flat contract.

  • Chaperone contracts may wrap a value in such a way that it signals contract violations later, as the value is used, but are guaranteed to not otherwise change behavior. For example, a function contract wraps a function value and later checks inputs and outputs; any properties that the function value had before being wrapped by the contract are preserved by the contract wrapper.

    All flat contracts may be used where chaperone contracts are expected (but not vice-versa). The function chaperone-contract? recognizes a chaperone contract.

  • Impersonator contracts may wrap values and do not provide any guarantees. Impersonator contracts may hide properties of values, or even make them completely opaque (e.g, new-∀/c).

    All contracts may be used where impersonator contracts are expected. The function impersonator-contract? recognizes an impersonator contract.

For more about this hierarchy, see the section “Impersonators and Chaperones” as well as a research paper [Strickland12] on chaperones, impersonators, and how they can be used to implement contracts.

Changed in version 6.1.1.8 of package base: Changed +nan.0 and +nan.f to be equal?-based contracts.

    8.1 Data-structure Contracts

    8.2 Function Contracts

    8.3 Parametric Contracts

    8.4 Lazy Data-structure Contracts

    8.5 Structure Type Property Contracts

    8.6 Attaching Contracts to Values

      8.6.1 Nested Contract Boundaries

      8.6.2 Low-level Contract Boundaries

    8.7 Building New Contract Combinators

      8.7.1 Blame Objects

      8.7.2 Contracts as structs

      8.7.3 Obligation Information in Check Syntax

      8.7.4 Utilities for Building New Combinators

    8.8 Contract Utilities

    8.9 racket/contract/base

    8.10 Collapsible Contracts

    8.11 Legacy Contracts

    8.12 Random generation