8.5 Structure Type Property Contracts

► |  | The Racket Reference

1 | Language Model
2 | Notation for Documentation
3 | Syntactic Forms
4 | Datatypes
5 | Structures
6 | Classes and Objects
7 | Units
8 | Contracts
9 | Pattern Matching
10 | Control Flow
11 | Concurrency and Parallelism
12 | Macros
13 | Input and Output
14 | Reflection and Security
15 | Operating System
16 | Memory Management
17 | Unsafe Operations
18 | Running Racket
| Bibliography
| Index

▼ | 8 | 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.7 | Building New Contract Combinators
8.8 | Contract Utilities
8.9 | racket/ contract/ base
8.10 | Collapsible Contracts
8.11 | Legacy Contracts
8.12 | Random generation

On this page:

struct-type-property/ c

7.2
top ← prev up next →

#### 8.5`` Structure Type Property Contracts

> procedure (struct-type-property/c value-contract) → contract?
> value-contract : contract?

Produces a contract for a structure type property. When the contract is applied to a struct type property, it produces a wrapped struct type property that applies value-contract to the value associated with the property when it used to create a new struct type (via struct, make-struct-type, etc).

The struct type property’s accessor function is not affected; if it is exported, it must be protected separately.

As an example, consider the following module. It creates a structure type property, prop, whose value should be a function mapping a structure instance to a numeric predicate. The module also exports app-prop, which extracts the predicate from a structure instance and applies it to a given value.

> > (module propmod racket
> (require racket/contract)
> (define-values (prop prop? prop-ref)
> (make-struct-type-property 'prop))
> (define (app-prop x v)
> (((prop-ref x) x) v))
> (provide/contract
> [prop? (-> any/c boolean?)]
> [prop (struct-type-property/c
> (-> prop? (-> integer? boolean?)))]
> [app-prop (-> prop? integer? boolean?)])
> (provide prop-ref))

The structmod module creates a structure type named s with a single field; the value of prop is a function that extracts the field value from an instance. Thus the field ought to be an integer predicate, but notice that structmod places no contract on s enforcing that constraint.

> > (module structmod racket
> (require 'propmod)
> (struct s (f) #:property prop (lambda (s) (s-f s)))
> (provide (struct-out s)))
> > (require 'propmod 'structmod)

First we create an s instance with an integer predicate, so the constraint on prop is in fact satisfied. The first call to app-prop is correct; the second simply violates the contract of app-prop.

> > (define s1 (s even?))
> > (app-prop s1 5)
> #f
> > (app-prop s1 'apple)
> app-prop: contract violation
> expected: integer?
> given: 'apple
> in: the 2nd argument of
> (-> prop? integer? boolean?)
> contract from: propmod
> blaming: top-level
> (assuming the contract is correct)
> at: eval:2.0

We are able to create s instances with values other than integer predicates, but applying app-prop on them blames structmod, because the function associated with prop—that is, (lambda (s) (s-f s))—does not always produce a value satisfying (-> integer? boolean?).

> > (define s2 (s "not a fun"))
> > (app-prop s2 5)
> prop: contract violation
> expected: a procedure
> given: "not a fun"
> in: the range of
> the struct property value of
> (struct-type-property/c
> (-> prop? (-> integer? boolean?)))
> contract from: propmod
> blaming: structmod
> (assuming the contract is correct)
> at: eval:2.0
> > (define s3 (s list))
> > (app-prop s3 5)
> prop: contract violation
> expected: boolean?
> given: '(5)
> in: the range of
> the range of
> the struct property value of
> (struct-type-property/c
> (-> prop? (-> integer? boolean?)))
> contract from: propmod
> blaming: structmod
> (assuming the contract is correct)
> at: eval:2.0

The fix would be to propagate the obligation inherited from prop to s:

> (provide (contract-out
> [struct s ([f (-> integer? boolean?)])]))

Finally, if we directly apply the property accessor, prop-ref, and then misuse the resulting function, the propmod module is blamed:

> > ((prop-ref s3) 'apple)
> prop: broke its own contract
> promised: prop?
> produced: 'apple
> in: the 1st argument of
> the struct property value of
> (struct-type-property/c
> (-> prop? (-> integer? boolean?)))
> contract from: propmod
> blaming: propmod
> (assuming the contract is correct)
> at: eval:2.0

The propmod module has an obligation to ensure a function associated with prop is applied only to values satisfying prop?. By directly providing prop-ref, it enables that constraint to be violated (and thus it is blamed), even though the bad application actually occurs elsewhere.

Generally there is no need to provide a structure type property accessor at all; it is typically only used by other functions within the module. But if it must be provided, it should be protected thus:

> (provide (contract-out
> [prop-ref (-> prop? (-> prop? (-> integer? boolean?)))]))

top ← prev up next →