[Style] contract-out over provide/contract
This commit is contained in:
parent
9999a02009
commit
ecb58309da
|
@ -22,7 +22,7 @@
|
||||||
;; bad ;; label a code fragment 'bad' [doesn't work]
|
;; bad ;; label a code fragment 'bad' [doesn't work]
|
||||||
column-table
|
column-table
|
||||||
row-table
|
row-table
|
||||||
rkt rkt/base rkt/gui)
|
rkt rkt/base rkt/gui xml)
|
||||||
|
|
||||||
(define (LINEWIDTH) "102")
|
(define (LINEWIDTH) "102")
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
||||||
(define (rkt) (racketmodname racket))
|
(define (rkt) (racketmodname racket))
|
||||||
(define (rkt/base) (racketmodname racket/base))
|
(define (rkt/base) (racketmodname racket/base))
|
||||||
(define (rkt/gui) (racketmodname racket/gui))
|
(define (rkt/gui) (racketmodname racket/gui))
|
||||||
|
(define (xml) (racketmodname xml))
|
||||||
|
|
||||||
;; compare: two code snippets, in two columns: left is good, right is bad
|
;; compare: two code snippets, in two columns: left is good, right is bad
|
||||||
(define (compare stuff1 stuff2)
|
(define (compare stuff1 stuff2)
|
||||||
|
|
|
@ -55,6 +55,8 @@ If a unit of code looks incomprehensible, it is probably too large. Break
|
||||||
division; consider alternatives.
|
division; consider alternatives.
|
||||||
|
|
||||||
@; -----------------------------------------------------------------------------
|
@; -----------------------------------------------------------------------------
|
||||||
|
@(define line
|
||||||
|
@t{---------------------------------------------------------------------------------------------------})
|
||||||
@section{Modules and their Interfaces}
|
@section{Modules and their Interfaces}
|
||||||
|
|
||||||
The purpose of a module is to provide some services:
|
The purpose of a module is to provide some services:
|
||||||
|
@ -64,7 +66,7 @@ The purpose of a module is to provide some services:
|
||||||
Often ``short'' means one line; occasionally you may need several lines.
|
Often ``short'' means one line; occasionally you may need several lines.
|
||||||
|
|
||||||
In order to understand a module's services, organize the module in three
|
In order to understand a module's services, organize the module in three
|
||||||
sections below the purpose statement: its imports, its exports, and its
|
sections below the purpose statement: its exports, its imports, and its
|
||||||
implementation:
|
implementation:
|
||||||
@;%
|
@;%
|
||||||
@codebox[
|
@codebox[
|
||||||
|
@ -76,14 +78,17 @@ implementation:
|
||||||
|
|
||||||
;; the module implements a tv server
|
;; the module implements a tv server
|
||||||
|
|
||||||
(require 2htdp/universe htdp/image)
|
|
||||||
|
|
||||||
(provide
|
(provide
|
||||||
;; launch the tv server function
|
;; launch the tv server function
|
||||||
tv-launch
|
tv-launch
|
||||||
;; set up a tv client to receive messages from the tv server
|
;; set up a tv client to receive messages from the tv server
|
||||||
tv-client)
|
tv-client)
|
||||||
|
|
||||||
|
(code:comment #, @line)
|
||||||
|
(code:comment #, @t{import and implementation section})
|
||||||
|
|
||||||
|
(require 2htdp/universe htdp/image)
|
||||||
|
|
||||||
(define (tv-launch)
|
(define (tv-launch)
|
||||||
(universe ...))
|
(universe ...))
|
||||||
|
|
||||||
|
@ -92,9 +97,16 @@ implementation:
|
||||||
))]
|
))]
|
||||||
@;%
|
@;%
|
||||||
|
|
||||||
If you choose to use @racket[provide/contract], define auxiliary concepts
|
If you choose to use @racket[provide] with @racket[contract-out], you
|
||||||
related to the contracts between the @racket[require] and the
|
may wish to have two @racket[require] sections:
|
||||||
@racket[provide] sections:
|
@itemlist[
|
||||||
|
@item{the first one, placed above the @racket[provide] section, imports the
|
||||||
|
values needed to formulate the contracts and}
|
||||||
|
@item{the second one, placed below the @racket[provide] section, imports
|
||||||
|
the values needed to implement the services.}
|
||||||
|
]
|
||||||
|
If your contracts call for additional concepts, define those between the
|
||||||
|
@racket[require] for contracts and the @racket[provide] specification:
|
||||||
@;%
|
@;%
|
||||||
@codebox[
|
@codebox[
|
||||||
@(begin
|
@(begin
|
||||||
|
@ -105,7 +117,7 @@ If you choose to use @racket[provide/contract], define auxiliary concepts
|
||||||
|
|
||||||
;; the module implements a tv server
|
;; the module implements a tv server
|
||||||
|
|
||||||
(require 2htdp/universe htdp/image xml)
|
(require xml)
|
||||||
|
|
||||||
(define player# 3)
|
(define player# 3)
|
||||||
(define plain-board/c
|
(define plain-board/c
|
||||||
|
@ -114,14 +126,20 @@ If you choose to use @racket[provide/contract], define auxiliary concepts
|
||||||
(define placement/c
|
(define placement/c
|
||||||
(flat-named-contract "placement" ...))
|
(flat-named-contract "placement" ...))
|
||||||
|
|
||||||
(provide/contract
|
(provide
|
||||||
|
(contract-out
|
||||||
;; initialize the board for the given number of players
|
;; initialize the board for the given number of players
|
||||||
[board-init (-> player#/c plain-board/c)]
|
[board-init (-> player#/c plain-board/c)]
|
||||||
;; initialize a board and place the tiles
|
;; initialize a board and place the tiles
|
||||||
[create-board (-> player#/c (listof placement/c)
|
[create-board (-> player#/c (listof placement/c)
|
||||||
(or/c plain-board/c string?))]
|
(or/c plain-board/c string?))]
|
||||||
;; create a board from an X-expression representation
|
;; create a board from an X-expression representation
|
||||||
[board-deserialize (-> xexpr? plain-board/c)])
|
[board-deserialize (-> xexpr? plain-board/c)]))
|
||||||
|
|
||||||
|
(code:comment #, @line)
|
||||||
|
(code:comment #, @t{import and implementation section})
|
||||||
|
|
||||||
|
(require 2htdp/universe htdp/image)
|
||||||
|
|
||||||
; implementation:
|
; implementation:
|
||||||
(define (board-init n)
|
(define (board-init n)
|
||||||
|
@ -135,8 +153,13 @@ If you choose to use @racket[provide/contract], define auxiliary concepts
|
||||||
(class ... some 900 lines ...))
|
(class ... some 900 lines ...))
|
||||||
))]
|
))]
|
||||||
@;%
|
@;%
|
||||||
|
In the preceding code snippet, @xml[] imports the
|
||||||
|
@racket[xexpr?] predicate, which is needed to articulate the contract for
|
||||||
|
@racket[board-deserialize]. The @racket[require] line below the lines
|
||||||
|
imports an event-handling mechanism plus a simple image manipulation
|
||||||
|
library.
|
||||||
|
|
||||||
Avoid @racket[(provide (all-defined-out))].
|
Prefer specific export specifications over @racket[(provide (all-defined-out))].
|
||||||
|
|
||||||
A test suite section---if located within the module---should come at the
|
A test suite section---if located within the module---should come at the
|
||||||
very end, including its specific dependencies, i.e., @racket[require]
|
very end, including its specific dependencies, i.e., @racket[require]
|
||||||
|
@ -145,9 +168,9 @@ A test suite section---if located within the module---should come at the
|
||||||
@; -----------------------------------------------------------------------------
|
@; -----------------------------------------------------------------------------
|
||||||
@subsection{Require}
|
@subsection{Require}
|
||||||
|
|
||||||
With @racket[require] specifications at the top of the module, you let
|
With @racket[require] specifications at the top of the implementation
|
||||||
every reader know what is needed to understand the module. The
|
section, you let every reader know what is needed to understand the
|
||||||
@racket[require] specification nails down the external dependencies.
|
module.
|
||||||
|
|
||||||
@; -----------------------------------------------------------------------------
|
@; -----------------------------------------------------------------------------
|
||||||
@subsection{Provide}
|
@subsection{Provide}
|
||||||
|
@ -169,7 +192,7 @@ This helps people find the relevant information quickly.
|
||||||
racket
|
racket
|
||||||
|
|
||||||
;; This module implements
|
;; This module implements
|
||||||
;; several game strategies.
|
;; several strategies.
|
||||||
|
|
||||||
(require "game-basics.rkt")
|
(require "game-basics.rkt")
|
||||||
|
|
||||||
|
@ -181,7 +204,7 @@ This helps people find the relevant information quickly.
|
||||||
human-strategy
|
human-strategy
|
||||||
|
|
||||||
;; Stgy
|
;; Stgy
|
||||||
;; complete tree traversal
|
;; tree traversal
|
||||||
ai-strategy)
|
ai-strategy)
|
||||||
|
|
||||||
(define (general p)
|
(define (general p)
|
||||||
|
@ -202,7 +225,7 @@ This helps people find the relevant information quickly.
|
||||||
racket
|
racket
|
||||||
|
|
||||||
;; This module implements
|
;; This module implements
|
||||||
;; several game strategies.
|
;; several strategies.
|
||||||
|
|
||||||
(require "game-basics.rkt")
|
(require "game-basics.rkt")
|
||||||
|
|
||||||
|
@ -223,7 +246,7 @@ This helps people find the relevant information quickly.
|
||||||
|
|
||||||
(provide
|
(provide
|
||||||
;; Stgy
|
;; Stgy
|
||||||
;; a complete tree traversal
|
;; a tree traversal
|
||||||
ai-strategy)
|
ai-strategy)
|
||||||
|
|
||||||
(define ai-strategy
|
(define ai-strategy
|
||||||
|
@ -261,8 +284,9 @@ racket
|
||||||
define-strategy)
|
define-strategy)
|
||||||
))]
|
))]
|
||||||
|
|
||||||
Use @scheme[provide/contract] for module interfaces. Contracts often
|
Use @scheme[provide] with @racket[contract-out] for module interfaces.
|
||||||
provide the right level of specification for first-time readers.
|
Contracts often provide the right level of specification for first-time
|
||||||
|
readers.
|
||||||
|
|
||||||
At a minimum, you should use type-like contracts, i.e., predicates that
|
At a minimum, you should use type-like contracts, i.e., predicates that
|
||||||
check for the constructor of data. They cost almost nothing, especially
|
check for the constructor of data. They cost almost nothing, especially
|
||||||
|
@ -319,9 +343,10 @@ As of version 5.3, Racket supports sub-modules. Use sub-modules to
|
||||||
(module+ test
|
(module+ test
|
||||||
(require rackunit))
|
(require rackunit))
|
||||||
|
|
||||||
(provide/contract
|
(provide
|
||||||
|
(contract-out
|
||||||
(code:comment #, @t{convert a fahrenheit temperature to a celsius temperature})
|
(code:comment #, @t{convert a fahrenheit temperature to a celsius temperature})
|
||||||
[fahrenheit->celsius (-> number? number?)])
|
[fahrenheit->celsius (-> number? number?)]))
|
||||||
|
|
||||||
(define (fahrenheit->celsius f)
|
(define (fahrenheit->celsius f)
|
||||||
(/ (* 5 (- f 32)) 9))
|
(/ (* 5 (- f 32)) 9))
|
||||||
|
@ -372,8 +397,9 @@ but the use of "module" in this phrase does @emph{not} only refer to
|
||||||
file-based or physical Racket modules. Clearly, @defterm{contract boundary}
|
file-based or physical Racket modules. Clearly, @defterm{contract boundary}
|
||||||
is better than module boundary because it separates the two concepts.
|
is better than module boundary because it separates the two concepts.
|
||||||
|
|
||||||
When you use @racket[provide/contract] at the module level, the boundary of
|
When you use @racket[provide] with @racket[contract-out] at the module
|
||||||
the physical module and the contract boundary coincide.
|
level, the boundary of the physical module and the contract boundary
|
||||||
|
coincide.
|
||||||
|
|
||||||
When a module becomes too large to manage without contracts but you do not
|
When a module becomes too large to manage without contracts but you do not
|
||||||
wish to distribute the source over several files, you may wish to use one
|
wish to distribute the source over several files, you may wish to use one
|
||||||
|
|
Loading…
Reference in New Issue
Block a user