On this page:
define-own-contract-policies
own-contract-out
define/  own-contract
ascribe-own-contract
8.12

10 A Framework for Declaring Contracts Alongside Functions🔗ℹ

 (require lathe-comforts/own-contract)
  package: lathe-comforts-lib

The lathe-comforts/own-contract module defines a small and unstable DSL for managing the use of contracts in a module. The combination of define/own-contract and own-contract-out works like specifying a contract in a contract-out form, but it allows the contract to be written at the function definition site in the style of define/contract. To use the DSL, it’s necessary to use define-own-contract-policies first.

syntax

(define-own-contract-policies option ...)

 
option = #:antecedent-land stx
  | 
#:make-signature-contract-id
make-signature-contract-id-expr
  | 
#:suppressing-external-contracts?
suppressing-external-contracts?-expr
  | 
#:activating-external-contracts?
activating-external-contracts?-expr
 
  make-signature-contract-id-expr : (or/c #f (-> identifier? identifier?))
  suppressing-external-contracts?-expr : boolean?
  activating-external-contracts?-expr : boolean?
Sets up the lathe-comforts/own-contract DSL for the current module. Certain policies can be specified that adjust the behavior of the DSL.

#:antecedent-land antecedent-land

The various syntactic forms of the lathe-comforts/own-contract DSL communicate by way of anaphoric bindings. This option causes the define-own-contract-policies form to define these bindings so that they have a lexical context derived from the lexical context of the syntax of antecedent-land.

Everything else about antecedent-land is ignored; it is not evaluated as an expression.

#:make-signature-contract-id
make-signature-contract-id-expr
 
  make-signature-contract-id : (or/c #f (-> identifier? identifier?))

Evaluates make-signature-contract-id-expr at phase level 1 relative to the surrounding context and uses the result to determine what variables the DSL uses to keep track of a binding’s associated contract.

If the result is a procedure, the procedure will be called each time the DSL determines the variable that an associated contract will be found in. It will be passed the identifier of the value binding, and its result will be taken as the identifier of the associated contract binding.

If the result is #f, a procedure is used that adds a unique but consistent scope to the identifiers it receives. Essentially, the default policy value is (make-syntax-introducer).

#:suppressing-external-contracts?
suppressing-external-contaracts?-expr
 
  suppressing-external-contaracts?-expr : boolean?

Evaluates suppressing-external-contaracts?-expr at phase level 1 relative to the surrounding context and uses the result to determine whether the DSL suppresses contracts on external uses of a variable. The default is #f, which causes the DSL to enforce contracts on external uses.

Note that currently, any use via a module import is considered an external use, even if the importing module is part of the same codebase as the module that’s being imported. This DSL may be extended or modified in the future with more options for treating such uses as internal.

#:activating-internal-contracts?
activating-internal-contaracts?-expr
 
  activating-internal-contaracts?-expr : boolean?

Evaluates activating-internal-contaracts?-expr at phase level 1 relative to the surrounding context and uses the result to determine whether the DSL attempts to enforce contracts on external uses of a variable. The default is #f, which causes the DSL to ignore contracts for internal uses.

Note that currently, only contracts ascribed using define/own-contract can be activated this way. Contracts ascribed using ascribe-own-contract don’t affect the internal binding of the variable they annotate, so direct uses of that variable will continue to behave in ways that aren’t protected by the contract.

Currently, unlike most ways of imposing a contract, this enforcement doesn’t establish a boundary between two parties. The surrounding module is blamed for any violations of the contract. See invariant-assertion. Like invariant-assertion, and unlike define/contract, the contract is enforced for recursive function calls.

syntax

(own-contract-out maybe-antecedent-land id ...)

 
maybe-antecedent-land = 
  | #:antecedent-land stx
A provide-spec for use with provide. Each id is provided from the module, protected with its associated define/own-contract or ascribe-own-contract contract as though using contract-out.

Like contract-out, currently this only supports providing identifiers at the same phase level as the provide form. It won’t work when nested inside for-syntax.

The lathe-comforts/own-contract DSL must be set up for the current module using define-own-contract-policies before calling this.

#:antecedent-land antecedent-land

The various syntactic forms of the lathe-comforts/own-contract DSL communicate by way of anaphoric bindings. This option causes the own-contract-out form to retrieve these bindings using a lexical context derived from the lexical context of the syntax of antecedent-land.

Everything else about antecedent-land is ignored; it is not evaluated as an expression.

syntax

(define/own-contract id
  contract-expr
  maybe-antecedent-land
  init-value-expr)
(define/own-contract (head args)
  contract-expr
  maybe-antecedent-land
  body ...+)
 
maybe-antecedent-land = 
  | #:antecedent-land stx
     
head = id
  | (head args)
     
args = arg ...
  | arg ... . rest-id
     
arg = arg-id
  | [arg-id default-expr]
  | keyword arg-id
  | keyword [arg-id default-expr]
 
  contract-expr : contract?
Works like define or define/contract, except that it associates the given contract with id for the purposes of own-contract-out.

The lathe-comforts/own-contract DSL must be set up for the current module using define-own-contract-policies before calling this.

If the #:activating-internal-contracts? policy is in effect (though it is not in effect by default), uses of id are protected by the given contract even within the current module. Currently, unlike most ways of imposing a contract, this enforcement doesn’t establish a boundary between two parties. The surrounding module is blamed for any violations of the contract. See invariant-assertion. Like invariant-assertion, and unlike define/contract, the contract is enforced for recursive function calls.

#:antecedent-land antecedent-land

The various syntactic forms of the lathe-comforts/own-contract DSL communicate by way of anaphoric bindings. This option causes the define/own-contract form to retrieve these bindings using a lexical context derived from the lexical context of the syntax of antecedent-land.

Everything else about antecedent-land is ignored; it is not evaluated as an expression.

syntax

(ascribe-own-contract id contract-expr maybe-antecedent-land)

 
maybe-antecedent-land = 
  | #:antecedent-land stx
 
  contract-expr : contract?
Associates the given contract with the given id for the purposes of own-contract-out.

The lathe-comforts/own-contract DSL must be set up for the current module using define-own-contract-policies before calling this.

Note that currently, even if the #:activating-internal-contracts? policy is in effect, code that uses ascribe-own-contract won’t have its internal contracts activated. Contracts ascribed using ascribe-own-contract don’t affect the internal binding of the variable they annotate, so direct uses of that variable will continue to behave in ways that aren’t protected by the contract.

#:antecedent-land antecedent-land

The various syntactic forms of the lathe-comforts/own-contract DSL communicate by way of anaphoric bindings. This option causes the ascribe-own-contract form to retrieve these bindings using a lexical context derived from the lexical context of the syntax of antecedent-land.

Everything else about antecedent-land is ignored; it is not evaluated as an expression.