drafted a no-contract section for the Style guide
This commit is contained in:
parent
9e7fa9b859
commit
b45e3767da
|
@ -3,19 +3,11 @@
|
||||||
;; ---------------------------------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------------------------------
|
||||||
; things to be shared among all sections of the style guide
|
; things to be shared among all sections of the style guide
|
||||||
|
|
||||||
(require (for-label racket)
|
|
||||||
scribble/base
|
|
||||||
scribble/manual
|
|
||||||
scribble/struct
|
|
||||||
(only-in scribble/core table-columns table-cells style plain
|
|
||||||
color-property)
|
|
||||||
scribble/html-properties
|
|
||||||
racket/list)
|
|
||||||
|
|
||||||
(provide (for-label (all-from-out racket))
|
(provide (for-label (all-from-out racket))
|
||||||
(all-from-out scribble/manual))
|
(all-from-out scribble/manual))
|
||||||
|
|
||||||
(provide
|
(provide
|
||||||
|
1/2-line
|
||||||
LINEWIDTH
|
LINEWIDTH
|
||||||
eli
|
eli
|
||||||
codebox
|
codebox
|
||||||
|
@ -26,12 +18,23 @@
|
||||||
row-table
|
row-table
|
||||||
rkt rkt/base rkt/gui xml)
|
rkt rkt/base rkt/gui xml)
|
||||||
|
|
||||||
|
(require (for-label racket)
|
||||||
|
scribble/base
|
||||||
|
scribble/manual
|
||||||
|
scribble/struct
|
||||||
|
(only-in scribble/core table-columns table-cells style plain
|
||||||
|
color-property)
|
||||||
|
scribble/html-properties
|
||||||
|
racket/list)
|
||||||
|
|
||||||
(define eli "eli@barzilay.org")
|
(define eli "eli@barzilay.org")
|
||||||
|
|
||||||
(define (LINEWIDTH) "102")
|
(define (LINEWIDTH) "102")
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(define (1/2-line (n 11)) (t (string-join (map string (make-list n #\-)))))
|
||||||
|
|
||||||
(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))
|
||||||
|
|
|
@ -177,10 +177,6 @@ With @racket[require] specifications at the top of the implementation
|
||||||
@; -----------------------------------------------------------------------------
|
@; -----------------------------------------------------------------------------
|
||||||
@subsection{Provide}
|
@subsection{Provide}
|
||||||
|
|
||||||
@(define 1/2-line
|
|
||||||
@t{---------------------------------})
|
|
||||||
|
|
||||||
|
|
||||||
A module's interface describes the services it provides; its body
|
A module's interface describes the services it provides; its body
|
||||||
implements these services. Others have to read the interface if the
|
implements these services. Others have to read the interface if the
|
||||||
external documentation doesn't suffice:
|
external documentation doesn't suffice:
|
||||||
|
@ -211,7 +207,7 @@ This helps people find the relevant information quickly.
|
||||||
;; tree traversal
|
;; tree traversal
|
||||||
ai-strategy)
|
ai-strategy)
|
||||||
|
|
||||||
(code:comment #, @1/2-line)
|
(code:comment #, @1/2-line[])
|
||||||
(code:comment #, @t{implementation})
|
(code:comment #, @t{implementation})
|
||||||
|
|
||||||
(require "basics.rkt")
|
(require "basics.rkt")
|
||||||
|
@ -236,7 +232,7 @@ This helps people find the relevant information quickly.
|
||||||
;; This module implements
|
;; This module implements
|
||||||
;; several strategies.
|
;; several strategies.
|
||||||
|
|
||||||
(code:comment #, @1/2-line)
|
(code:comment #, @1/2-line[])
|
||||||
(code:comment #, @t{implementation})
|
(code:comment #, @t{implementation})
|
||||||
|
|
||||||
(require "basics.rkt")
|
(require "basics.rkt")
|
||||||
|
@ -531,3 +527,168 @@ recursive fashion, submodule contract boundaries cannot enforce constraints
|
||||||
on mutually recursive functions. It would thus be impossible to distribute
|
on mutually recursive functions. It would thus be impossible to distribute
|
||||||
the @racket[find-path] and @racket[find-path*] functions from the preceding
|
the @racket[find-path] and @racket[find-path*] functions from the preceding
|
||||||
code display into two distinct submodules.
|
code display into two distinct submodules.
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@section{No Contracts}
|
||||||
|
|
||||||
|
Adding contracts to a library is good.
|
||||||
|
|
||||||
|
On some occasions, contracts impose a significant performance penalty.
|
||||||
|
For such cases, we recommend organizing the module into two parts:
|
||||||
|
@itemlist[
|
||||||
|
|
||||||
|
@item{a submodule named @tt{no-contract}, which defines the
|
||||||
|
functionality and exports some of it to the surrounding module}
|
||||||
|
|
||||||
|
@item{a @racket[provide] specification with a @racket[contract-out] clause
|
||||||
|
in the outer module that re-exports the desired pieces of functionality.}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
@compare[
|
||||||
|
@;%
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
(racketmod0 #:file
|
||||||
|
@tt{correct}
|
||||||
|
racket
|
||||||
|
|
||||||
|
(define state? ...)
|
||||||
|
(define action? ...)
|
||||||
|
(define strategy/c
|
||||||
|
(-> state? action?))
|
||||||
|
|
||||||
|
(provide
|
||||||
|
(contract-out
|
||||||
|
;; people's strategy
|
||||||
|
(human strategy/c)
|
||||||
|
|
||||||
|
;; tree traversal
|
||||||
|
(ai strategy/c)))
|
||||||
|
|
||||||
|
(code:comment #, @1/2-line[])
|
||||||
|
(code:comment #, @t{implementation})
|
||||||
|
|
||||||
|
(define (general p) ... )
|
||||||
|
|
||||||
|
(define human
|
||||||
|
(general create-gui))
|
||||||
|
|
||||||
|
(define ai
|
||||||
|
(general traversal))))
|
||||||
|
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
(racketmod0 #:file
|
||||||
|
@tt{fast}
|
||||||
|
|
||||||
|
(define state? ...)
|
||||||
|
(define action? ...)
|
||||||
|
(define strategy/c
|
||||||
|
(-> state? action?))
|
||||||
|
|
||||||
|
(provide
|
||||||
|
(contract-out
|
||||||
|
;; people's strategy
|
||||||
|
(human strategy/c)
|
||||||
|
|
||||||
|
;; tree traversal
|
||||||
|
(ai strategy/c)))
|
||||||
|
|
||||||
|
(code:comment #, @1/2-line[])
|
||||||
|
(code:comment #, @t{implementation})
|
||||||
|
|
||||||
|
(module no-contract racket
|
||||||
|
(provide
|
||||||
|
human
|
||||||
|
ai)
|
||||||
|
|
||||||
|
(define (general p) ... )
|
||||||
|
|
||||||
|
(define human
|
||||||
|
(general create-gui))
|
||||||
|
|
||||||
|
(define ai
|
||||||
|
(general traversal)))
|
||||||
|
|
||||||
|
(require 'no-contract)))
|
||||||
|
]
|
||||||
|
|
||||||
|
The example labeled @tt{correct} illustrates what the module might look
|
||||||
|
like originally. Every exported function comes with a contract, and the
|
||||||
|
definitions of these functions can be found below the @racket[provide]
|
||||||
|
specification in the module body. By comparison, the @tt{fast} module on
|
||||||
|
the right encapsulates the definitions in a submodule called
|
||||||
|
@tt{no-contract}; the @racket[provide] in this submodule exports the exact
|
||||||
|
same identifiers as the @tt{correct} module on the left. The main module
|
||||||
|
@racket[require]s the submodule immediately, making the identifiers
|
||||||
|
available in the outer scope so that the contracted @code{provide} can
|
||||||
|
re-export them.
|
||||||
|
|
||||||
|
@compare[
|
||||||
|
@;%
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
(racketmod0 #:file
|
||||||
|
@tt{needs-correctness}
|
||||||
|
racket
|
||||||
|
|
||||||
|
(require coll/fast)
|
||||||
|
|
||||||
|
human
|
||||||
|
;; comes with contracts
|
||||||
|
;; as if we had required
|
||||||
|
;; coll/correct
|
||||||
|
|
||||||
|
(define state1 ...)
|
||||||
|
(define state2 (human state1))))
|
||||||
|
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
(racketmod0 #:file
|
||||||
|
@tt{needs-speed}
|
||||||
|
racket
|
||||||
|
|
||||||
|
(require
|
||||||
|
(submod
|
||||||
|
coll/fast no-contract))
|
||||||
|
|
||||||
|
human
|
||||||
|
;; comes without contracts
|
||||||
|
|
||||||
|
(define state*
|
||||||
|
(build-list ...))
|
||||||
|
(define action*
|
||||||
|
(map human state*))))
|
||||||
|
]
|
||||||
|
|
||||||
|
Once the submodule exists, using the library with or without contracts is
|
||||||
|
straightforward. Both modules from above @racket[require] @tt{fast}, but
|
||||||
|
the left one requires just @tt{fast} and the right one the submodule called
|
||||||
|
@tt{no-contract}. Hence the left module imports, say, @racket[human] with
|
||||||
|
contracts; the right one imports the same function without contract and
|
||||||
|
thus doesn't have to pay the performance penalty.
|
||||||
|
|
||||||
|
In some cases, the presence of contracts prevents a module from being used
|
||||||
|
in a context where contracts aren't available, say, for @rkt/base[] or the
|
||||||
|
contracts library itself. Again, you may wish you had the same library
|
||||||
|
without contracts. For these cases, we recommend a different strategy than
|
||||||
|
the submodule one. Assuming the library is located at @tt{a/b/c}, we
|
||||||
|
recommend
|
||||||
|
@itemlist[#:style 'ordered
|
||||||
|
|
||||||
|
@item{creating a @tt{private/} sub-directory with the file @tt{a/b/private/c-no-ctc.rkt},}
|
||||||
|
|
||||||
|
@item{placing the functionality into @tt{c-no-ctc.rkt},}
|
||||||
|
|
||||||
|
@item{importing it into @tt{a/b/c.rkt}, and}
|
||||||
|
|
||||||
|
@item{exporting it from there with contracts.}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
Once this arrangement is set up, a client module in a special context
|
||||||
|
@rkt/base[] or for @racketmodname[#, 'racket/contract] can use @racket[(require
|
||||||
|
a/b/private/c-no-ctc)]. In a regular module, though, it would suffice
|
||||||
|
to write @racket[(require a/b/c)] and doing so would import contracted
|
||||||
|
identifiers.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user