14.1 Signatures and Units

The interface of a unit is described in terms of signatures. Each signature is defined (normally within a module) using define-signature. For example, the following signature, placed in a "toy-factory-sig.rkt" file, describes the exports of a component that implements a toy factory:

By convention, signature names end with ^.

"toy-factory-sig.rkt"

#lang racket
 
(define-signature toy-factory^
  (build-toys  ; (integer? -> (listof toy?))
   repaint     ; (toy? symbol? -> toy?)
   toy?        ; (any/c -> boolean?)
   toy-color)) ; (toy? -> symbol?)
 
(provide toy-factory^)

An implementation of the toy-factory^ signature is written using define-unit with an export clause that names toy-factory^:

By convention, unit names end with @.

"simple-factory-unit.rkt"

#lang racket
 
(require "toy-factory-sig.rkt")
 
(define-unit simple-factory@
  (import)
  (export toy-factory^)
 
  (printf "Factory started.\n")
 
  (define-struct toy (color) #:transparent)
 
  (define (build-toys n)
    (for/list ([i (in-range n)])
      (make-toy 'blue)))
 
  (define (repaint t col)
    (make-toy col)))
 
(provide simple-factory@)

The toy-factory^ signature also could be referenced by a unit that needs a toy factory to implement something else. In that case, toy-factory^ would be named in an import clause. For example, a toy store would get toys from a toy factory. (Suppose, for the sake of an example with interesting features, that the store is willing to sell only toys in a particular color.)

"toy-store-sig.rkt"

#lang racket
 
(define-signature toy-store^
  (store-color     ; (-> symbol?)
   stock!          ; (integer? -> void?)
   get-inventory)) ; (-> (listof toy?))
 
(provide toy-store^)

"toy-store-unit.rkt"

#lang racket
 
(require "toy-store-sig.rkt"
         "toy-factory-sig.rkt")
 
(define-unit toy-store@
  (import toy-factory^)
  (export toy-store^)
 
  (define inventory null)
 
  (define (store-color) 'green)
 
  (define (maybe-repaint t)
    (if (eq? (toy-color t) (store-color))
        t
        (repaint t (store-color))))
 
  (define (stock! n)
    (set! inventory
          (append inventory
                  (map maybe-repaint
                       (build-toys n)))))
 
  (define (get-inventory) inventory))
 
(provide toy-store@)

Note that "toy-store-unit.rkt" imports "toy-factory-sig.rkt", but not "simple-factory-unit.rkt". Consequently, the toy-store@ unit relies only on the specification of a toy factory, not on a specific implementation.