diff --git a/pkgs/racket-doc/scribblings/style/some-performance.scrbl b/pkgs/racket-doc/scribblings/style/some-performance.scrbl index f149785efb..751a3b0de1 100644 --- a/pkgs/racket-doc/scribblings/style/some-performance.scrbl +++ b/pkgs/racket-doc/scribblings/style/some-performance.scrbl @@ -144,14 +144,12 @@ expands to many nested definitions and expressions every time it is used. 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: +For such cases, we recommend organizing the module into a main module as +usual and a submodule called @tt{no-contract} so that @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.} +@item{the @tt{no-contract} submodule @racket[provide]s the functionality @emph{without} contracts,} +@item{the main module @racket[provide]s the functionality @emph{with} contracts.} ] This section explains three strategies for three different situations and levels of implementation complexity. @@ -160,9 +158,9 @@ levels of implementation complexity. explains the basics of our understanding of ``safety'' and link to it.} @; @bold{Warning} Splitting contracted functionality into two modules in -this way renders the code in the @tt{no-contract} @bold{unsafe}. The +this way renders the code in the @tt{no-contract} module @bold{unsafe}. The creator of the original code might have assumed certain constraints on some -function's arguments, and the contracts checked these constraints. While +functions' arguments, and the contracts checked these constraints. While the documentation of the @tt{no-contract} submodule is likely to state these constraints, it is left to the client to check them. If the client code doesn't check the constraints and the arguments don't satisfy them, @@ -216,7 +214,8 @@ the @racket[#:unprotected-submodule] functionality of @racket[contract-out]. (provide (contract-out - (code:hilite #:unprotected-submodule) (code:hilite no-contract) + (code:hilite #:unprotected-submodule) + (code:hilite no-contract) (human strategy/c) (ai strategy/c))) @@ -233,8 +232,8 @@ the @racket[#:unprotected-submodule] functionality of @racket[contract-out]. ((general 'tra) x)))) ] -The example labeled @tt{good} illustrates what the module might look -like originally. Every exported function comes with a contract, and the +The module called @tt{good} illustrates what the code might look +like originally. Every exported functions come with contracts, and the definitions of these functions can be found below the @racket[provide] specification in the module body. The @tt{fast} module on the right requests the creation of a submodule named @tt{no-contract}, which exports @@ -250,12 +249,12 @@ straightforward: @tt{needs-goodness} racket - (require coll/fast) + (require "fast.rkt") human ;; comes with contracts ;; as if we had required - ;; coll/good + ;; "good.rkt" itself (define state1 0) (define state2 @@ -269,7 +268,7 @@ straightforward: (require (submod - coll/fast + "fast.rkt" no-contract)) human @@ -281,16 +280,16 @@ straightforward: (define action* (map human state*)))) ] -Both modules @racket[require] the @tt{fast} module, but the left one goes -through the contracted @racket[provide] while and the right one uses the -@tt{no-contract} submodule. 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. +Both modules @racket[require] the @tt{fast} module, but @tt{needs-goodness} +on the left goes through the contracted @racket[provide] while +@tt{needs-speed} on the right uses the @tt{no-contract} submodule. Tchnically, +the left module imports @racket[human] with contracts; the right one +imports the same function without contract and thus doesn't have to pay the +performance penalty. Notice, however, that when you run these two client modules---assuming you -have installed @tt{fast} in some collection @tt{coll} appropriately---the -left one raises an contract error while the right one binds -@racket[action*] to +saved them with the correct names in some folder---the left one raises a +contract error while the right one binds @racket[action*] to @;% @(begin @@ -301,7 +300,7 @@ left one raises an contract error while the right one binds @;% The @tt{no-contract} submodule generated by this first, easy approach -depends on @racketmodname[#, 'racket/contract] at both compile and run time. +retains the dependency on @racketmodname[#, 'racket/contract] at both compile and run time. Here is a variant of the above module that demonstrates this point: @;% @(begin @@ -335,10 +334,10 @@ contracts, requiring the @tt{no-contract} still raises a contract error: (require (submod "." server no-contract)) )) @;% -@bold{Explanation} The @racket[require] runs the body of the main module, -and doing so checks the first-order properties of the exported values---and -because @racket[human] is not a function, this evaluation raises a contract -error. +@bold{Explanation} The @tt{no-contract} submodule depends on the main +module, so the require runs the body of the main module, and doing so +checks the first-order properties of the exported values. Because +@racket[human] is not a function, this evaluation raises a contract error. The @emph{second} way to create a @tt{no-contract} submodule requires systematic work from the developer and eliminates the run-time dependency @@ -349,7 +348,7 @@ above, with the right one derived manually from the one on the left: @(begin #reader scribble/comment-reader (racketmod0 #:file - @tt{good} + @tt{good2} racket (define state? zero?) @@ -377,7 +376,7 @@ above, with the right one derived manually from the one on the left: @(begin #reader scribble/comment-reader (racketmod0 #:file - @tt{fast} + @tt{fast2} racket (define state? zero?) @@ -410,20 +409,25 @@ above, with the right one derived manually from the one on the left: (require 'no-contract) )) ] -Here the @tt{fast} module on the right encapsulates the +The @tt{fast2} 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{good} module +this submodule exports the exact same identifiers as the @tt{good2} 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. +While this second way of creating a @tt{no-contract} submodule eliminates +the run-time dependency on @racketmodname[#, 'racket/contract], its +compilation---as a part of the outer module---still depends on this +library, which is problematic in a few remaining situations. + The @emph{third} and last way to create a @tt{no-contract} submodule is -useful when the presence of contracts prevents a module from being used in -a context where contracts aren't available at all. One example is -@rkt/base[]; another is the contracts library itself. Again, you may wish -you had the same library without contracts. For these cases, we recommend a -file-based strategy one. Assuming the library is located at @tt{a/b/c}, we -recommend +useful when contracts prevents a module from being used in a context where +contracts aren't available at all---neither at compile nor at run time. One +example is @rkt/base[]; another is the contracts library itself. Again, you +may wish you had the same library without contracts. For these cases, we +recommend a file-based strategy one. Assuming the library is located at +@tt{a/b/c}, we recommend @itemlist[#:style 'ordered