A contract says what a value must be: what a function accepts, what it returns, what shape a structure's fields take. Racket attaches contracts where values cross a boundary, normally the boundary of a module, and checks them as the values pass. When a check fails the error blames the party at fault: the module that broke its promise.
Attaching contracts
| Form | Effect |
|---|---|
(provide (contract-out [id contract] …)) | exports each name with its contract. The boundary is the module: other modules are checked, the module itself is trusted. [rename internal external contract], [struct name ([field contract] …)] and #:forall / #:exists for polymorphic contracts are also accepted |
(define/contract id contract expr), (define/contract (f arg …) contract body …) | attaches a contract to one definition, with the module (or a named with-contract region) as the boundary on the inside |
(contract c v pos-blame neg-blame) | applies a contract to a value, naming who provides it (positive) and who uses it (negative) |
(with-contract name ([result-id contract] …) body …) | makes a nested boundary inside a module |
(struct/contract …), (define-struct/contract …) | a struct with a contract for each field |
(contract-in module-path [id contract] …) | a require form that adds contracts on import, for modules that have none |
(provide/contract …) | the older spelling of contract-out in provide |
(invariant-assertion contract expr) | an assertion that is checked only when contracts are, in racket/contract |
Flat contracts
A flat contract is a predicate: it can be checked at once. Any procedure of one argument is a contract (number?, string?, (lambda (x) (> x 0))), and so are literals: a number, string, symbol, regular expression or boolean means "equal? to this" (a regexp means "a string it matches").
| Contract | Accepts |
|---|---|
any/c, none/c | everything; nothing |
(and/c c …), (or/c c …), (first-or/c c …), (not/c c) | both; either (a flat contract or any combination whose branches can be told apart); the first branch that matches; the opposite |
(=/c n), (</c n), (>/c n), (<=/c n), (>=/c n), (between/c lo hi), (real-in lo hi), (integer-in lo hi), natural-number/c, exact-nonnegative-integer? | numbers by comparison and range |
(char-in a b), (string-len/c n), (one-of/c v …), (symbols s …), (complex/c re im) | a character in a range; a string shorter than n; one of some values; one of some symbols; a complex number with those part contracts |
(flat-contract pred), (flat-named-contract name pred), (flat-contract-with-explanation …) | make a flat contract from a predicate, with a name for error messages |
(flat-rec-contract id c …), (flat-murec-contract …) | recursive flat contracts, for trees of lists and such |
Contracts for data structures
| Contract | Accepts |
|---|---|
(listof c), (non-empty-listof c), (list*of c last-c), (list/c c …), (*list/c prefix suffix …), (cons/c a d) | lists and pairs whose elements satisfy those contracts; list/c has a fixed length and a contract for each position |
(vectorof c), (vector/c c …), (vector-immutableof c), (vector-immutable/c c …), (box/c c), (box-immutable/c c) | vectors and boxes |
(hash/c key value), (hash/dc [k key] [v (k) value]) | hash tables; the dependent form lets the value's contract use the key |
(struct/c name c …), (struct/dc name field-spec …) | an instance of a structure whose fields match; the dependent form lets fields' contracts use other fields |
(treelist/c c), (mutable-treelist/c c), (syntax/c c), (parameter/c in out), (promise/c c), (channel/c c), (evt/c c …), (procedure-arity-includes/c n), (continuation-mark-key/c c) | contracts for other kinds of value |
(instanceof/c c), (class/c …), (object/c …), (is-a?/c type), (subclass?/c class), (implementation?/c intf) | classes and objects; see Classes and objects. ->m, ->*m, ->dm, case->m are the function contracts for methods |
(recursive-contract c), (opt/c c), (suggest/c c), (property/c accessor c) | a contract that refers to itself (delayed); one that is checked more cheaply; and helpers |
Contracts on mutable structures, procedures, boxes and so on are higher-order (they cannot be checked all at once). Racket checks them lazily by wrapping the value in a chaperone or impersonator that checks each use. The cost of a contract on each element access is why a contract on a very large vector can be slow, and why an or/c of two function contracts needs them told apart by a flat test.
Function contracts
| Form | Describes |
|---|---|
(-> dom … range) | a function of exactly those arguments. A domain item may be keyword dom for a required keyword argument. range is a contract, (values c …) for several results, or any for no promise about results. A ... after a domain item lets that contract repeat. (integer? boolean? . -> . integer?) is the same with the arrow in the middle |
(->* (mandatory …) (optional …) #:rest rest-c range) | optional positional or keyword arguments, and a rest argument; #:pre, #:post and the /desc forms add conditions that must hold before and after the call |
(->i ([id dom] …) (#:key [id dom] …) #:rest … #:pre … range-spec #:post …) | a dependent contract: the contract of a later argument or of the result can use the names of the earlier arguments. (->i ([x number?] [y (x) (>/c x)]) [result number?]) |
(->d …) | the older, laxer form of ->i, kept for compatibility; new code should use ->i |
(case-> (-> …) …) | a function with several arities, one contract per arity (for case-lambda and for functions with optional arguments) |
(unconstrained-domain-> range …) | a function that accepts any arguments, but whose results are checked |
(dynamic->* …) | the function form of ->*, taking the contracts as values |
(parametric->/c (x …) c) | a polymorphic function: inside, the type variable x is sealed so the function cannot look inside values of that type; new-∀/c and new-∃/c make the sealing contracts |
#lang racket
(provide
(contract-out
[average (-> (non-empty-listof real?) real?)]
[safe-div (->i ([n number?] [d (and/c number? (not/c zero?))]) [result number?])]
[clamp (->* (real?) (#:lo real? #:hi real?) real?)]
[struct point ([x real?] [y real?])]))
(struct point (x y))
(define (average xs) (/ (apply + xs) (length xs)))
(define (safe-div n d) (/ n d))
(define (clamp v #:lo [lo 0] #:hi [hi 1]) (max lo (min hi v)))
(define/contract (inc x)
(-> exact-integer? exact-integer?)
(+ x 1))
; (average '()) => average: contract violation, expected non-empty-listof real?, given '(), blaming the caller
Blame
Every contract check knows two parties: the positive party, that supplied the value, and the negative party, that received it. For a function, the argument checks blame the caller (negative) and the result checks blame the function's module (positive). A message such as f: contract violation … blaming: top-level names the party at fault, the contract, the value and the source location. The blame object (blame?, blame-positive, blame-negative, blame-value, blame-contract, blame-source, raise-blame-error) is the interface for writing new contracts, along with make-contract, make-chaperone-contract, make-flat-contract and the prop:contract structure properties.
Utilities
contract?, flat-contract?, chaperone-contract?, list-contract? and impersonator-contract? test what kind a contract is; coerce-contract turns a predicate or literal into a contract; contract-name gives its description; contract-first-order-passes? checks only the part that can be checked at once; contract-stronger? and contract-equivalent? compare two contracts; value-contract and has-contract? look at a value that has one; contract-struct (and define-contract-struct) makes lazily-checked structures. The libraries racket/contract/base and racket/contract/region split the pieces.
Not described
Known, not yet covered
- Reference: the exact semantics of each combinator (which are flat, chaperone or impersonator contracts), the rules of blame for higher-order values, the contract-system performance notes, the full syntax of
->i(its optional and keyword parts,#:pre/desc),build-…-contract-propertyand the property-based combinator API, the collapsible-contract system, and Check Syntax obligation information were not described. The combinator tables were taken from the headings of the Reference chapter, not read form by form. - Reference: whether a given combinator accepts keyword domains and how
and/candor/cclassify their parts are not stated here. - Viewer: contract names ending in
/cand the arrows->,->*,->i,->d,case->are coloured as types; the other combinator names (listof,vectorof,hash/c) get a type colour only when they match those rules.
See also
- Modules –
provideandcontract-out - Typed Racket – checking types at compile time instead
- Structs – contract properties of structures