[Style] first round of edits

This commit is contained in:
Matthias Felleisen 2011-07-26 22:19:34 -04:00 committed by Eli Barzilay
parent b14b90655c
commit 11a04cd6fa
5 changed files with 124 additions and 127 deletions

View File

@ -12,10 +12,10 @@ and readability.
@; ----------------------------------------------------------------------------- @; -----------------------------------------------------------------------------
@section{Definitions} @section{Definitions}
Here are a few of Racket's definitional constructs: @scheme[let], @scheme[let*], Racket comes with quite a few definitional constructs, including
@scheme[letrec], and @scheme[define]. Except for the last one, all others force @scheme[let], @scheme[let*], @scheme[letrec], and @scheme[define]. Except
an increase to the indentation level. We therefore request that you favor for the last one, definitional construct increase the indentation level. We
@scheme[define] over all other features when feasible. therefore request that you favor @scheme[define] when feasible.
@compare[ @compare[
@racketmod[#:file @racketmod[#:file
@ -55,10 +55,10 @@ racket
(cond (cond
[(empty? l) true] [(empty? l) true]
[else [else
(define fst (first l)) (define f (fir l))
(define rst (rest l)) (define r (rest l))
(and (flat-rate fst) (and (flat-rate f)
(curved fst (chk rst)))]) (curved f (chk r)))])
] ]
@racketmod[#:file @racketmod[#:file
@tt{bad} @tt{bad}
@ -66,12 +66,38 @@ racket
(if (empty? l) (if (empty? l)
true true
(let ([fst (first l)] (let ([f (fir l)]
[rst (rest l)]) [r (rest l)])
(and (flat-rate fst) (and (flat-rate f)
(curved fst (chk rst))))) (curved f (chk r)))))
] ]
] ]
Of course you should also favor @scheme[cond] (and its relatives) over Of course you should also favor @scheme[cond] (and its relatives) over
@scheme[if] to match the shape of the data definition. @scheme[if] to match the shape of the data definition.
@; -----------------------------------------------------------------------------
@section{Expressions}
Keep expressions small. Name intermediate results.
@compare[
@racketmod[#:file
@tt{good}
racket
(define (distance0 p)
(define x (posn-x p))
(define y (posn-y p))
(sqrt (+ (sqr x) (sqr y))))
]
@; -----------------------------------------------------------------------------
@racketmod[#:file
@tt{bad}
racket
(define (distance0 p)
(sqrt
(+ (sqr (posn-x p))
(sqr (posn-y p)))))
]
]

View File

@ -122,13 +122,7 @@ Having said that, the production of a system like Racket occasionally
@; ----------------------------------------------------------------------------- @; -----------------------------------------------------------------------------
@section{Speed} @section{Speed}
Making code fast is an endless task. Making code fast is an endless task. Making code @emph{reasonably fast} is the goal.
Making code @emph{reasonably} fast is the goal.
It is especially the goal for all pieces of the code base that are reused
elsewhere. Write them using @rkt/base[] so that they don't affect the
load-time for scripts. See the next section.
As with correctness, performance demands some ``testing.'' At a minimum, As with correctness, performance demands some ``testing.'' At a minimum,
exercise your code on some reasonably large inputs. Add a file to the test exercise your code on some reasonably large inputs. Add a file to the test

View File

@ -10,9 +10,9 @@ When you write a module, you first pick a language. In Racket you can
choose a lot of languages. The most important choice concerns @rkt/base[] choose a lot of languages. The most important choice concerns @rkt/base[]
vs @rkt[]. vs @rkt[].
If you are writing a script, try using @rkt/base[]. The @rkt/base[] For scripts, use @rkt/base[]. The @rkt/base[] language loads significantly
language loads significantly faster than the @rkt[] language because it is faster than the @rkt[] language because it is much smaller than the
much smaller than the @rkt[]. @rkt[].
If your module is intended as a library, stick to @rkt/base[]. That way If your module is intended as a library, stick to @rkt/base[]. That way
script writers can use it without incurring the overhead of loading all of script writers can use it without incurring the overhead of loading all of
@ -21,5 +21,3 @@ If your module is intended as a library, stick to @rkt/base[]. That way
Conversely, you should use @rkt[] (or even @rkt/gui[]) when you just want a Conversely, you should use @rkt[] (or even @rkt/gui[]) when you just want a
convenient language to write some program. The @rkt[] language comes with convenient language to write some program. The @rkt[] language comes with
almost all the batteries, and @rkt/gui[] adds the rest of the GUI base. almost all the batteries, and @rkt/gui[] adds the rest of the GUI base.

View File

@ -26,29 +26,25 @@ your code.
@racketmod[#:file @racketmod[#:file
@tt{good} @tt{good}
racket racket
@;%
(define (conversion f) (define (conversion f)
(* 5/9 (- f 32))) (* 5/9 (- f 32)))
] ]
@racketmod[#:file @filebox[@tt{really bad}
@tt{really bad} @codeblock{#lang racket
racket
(define (conversion f) (define (conversion f)
(* 5/9 (- f 32) (* 5/9 (- f 32)
) )
) )
] }]
] ]
You are allowed to place all closing parenthesis on a line by itself at the You are allowed to place all closing parenthesis on a line by itself at the
end of long sequences, be those definitions or pieces of data. end of long sequences, be those definitions or pieces of data.
@compare[ @compare[
@racketmod[#:file @filebox[@tt{acceptable}
@tt{acceptable} @codeblock{#lang racket
racket
(define modes (define modes
'(edit '(edit
help help
@ -56,12 +52,10 @@ end of long sequences, be those definitions or pieces of data.
test test
trace trace
step step
)) ;; <--- bug in scribble: the last two are on their own line ))
] }]
@racketmod[#:file @filebox[@tt{also acceptable}
@tt{also acceptable} @codeblock{#lang racket
racket
(define turn% (define turn%
(class object% (class object%
(init-field state) (init-field state)
@ -73,8 +67,8 @@ end of long sequences, be those definitions or pieces of data.
(define/public (is-placable? place) (define/public (is-placable? place)
(send state legal? place)) (send state legal? place))
)) ;; <--- bug in scribble: the last two are on their own line ))
] }]
] ]
@; ----------------------------------------------------------------------------- @; -----------------------------------------------------------------------------
@ -85,9 +79,7 @@ on. So use DrRacket's indentation style. Here is what this means.
@nested[#:style 'inset]{ @nested[#:style 'inset]{
For every file in the repository, DrRacket's "indent all" functions leaves For every file in the repository, DrRacket's "indent all" functions leaves
the file alone.} the file alone.}
That's all there is to it. @margin-note{See @secref{correctness}. If you That's all there is to it.
really believe that DrRacket indents some construct improperly, submit a
bug report. When the bug report is closed, the discussion is finished.}
If you prefer to use some other editor (emacs, vi/m, etc), program it so If you prefer to use some other editor (emacs, vi/m, etc), program it so
that it follows DrRacket's indentation style. that it follows DrRacket's indentation style.
@ -114,8 +106,6 @@ Examples:
] ]
] ]
@margin-note{We need more of these rules}
@; ----------------------------------------------------------------------------- @; -----------------------------------------------------------------------------
@section{Line Breaks} @section{Line Breaks}
@ -150,8 +140,8 @@ Each definition and each local definition deserves at least one line.
racket racket
(define (launch x) (define (launch x)
(define wdt (* 10 x)) (define w 9)
(define hgt (* 3 x)) (define h 33)
...) ...)
] ]
@ -160,7 +150,7 @@ racket
racket racket
(define (launch x) (define (launch x)
(define wdt (* 10 x)) (define hgt (* 3 x)) (define w 9) (define h 33)
...) ...)
] ]
] ]
@ -189,7 +179,7 @@ racket
@tt{bad} @tt{bad}
racket racket
(composition ufo-with-flames (composition ufo
10 v-delta bg) 10 v-delta bg)
]] ]]
@ -203,10 +193,8 @@ racket
10 10 10 10
(rectangle 10 100 "solid" "red")) (rectangle 10 100 "solid" "red"))
] ]
In this case, the two arguments on line 2 are both short and conceptually In this case, the two arguments on line 2 are both conceptually
related. related and short.
@margin-note{We need more of these rules}
@; ----------------------------------------------------------------------------- @; -----------------------------------------------------------------------------
@section{Line Width} @section{Line Width}
@ -235,12 +223,10 @@ separated by dashes. Racket code benefits from the same convention.
In addition to regular alphanumeric characters, Racketeers use a few In addition to regular alphanumeric characters, Racketeers use a few
special characters. special characters.
@column-table[ @;column-table[ @col[? ! "@" ^ %] @col[1 2 3 4 5] @col[1 2 3 4 5] ]
@col[? ! "@" ^ %]
@col[1 2 3 4 5]
@col[1 2 3 4 5] ]
@row-table[ @row-table[
@row[symbol kind example]
@row[? predicates boolean?] @row[? predicates boolean?]
@row[! setters set!] @row[! setters set!]
@row[% classes a%] @row[% classes a%]

View File

@ -4,20 +4,44 @@
@title{Units of Code} @title{Units of Code}
@; -----------------------------------------------------------------------------
@section{Size Matters}
Keep units of code small. Keep modules, classes, functions and methods small.
A module of 10,000 lines of code is too large. A module of 1,000 lines is
tolerable. A module of 500 lines of code has the right size.
One module should usually a class and its auxiliary functions, which in
turn determines the length of a good-sized class.
And a function (method) of more than 66 lines is barely acceptable. For
many years we had a limited syntax transformation language that forced
people to create @emph{huge} functions. This is no longer the case, so
consider this rule universal.
If a unit of code looks incomprehensible, it is probably too large. Break
it up. To bring across what the pieces compute, implement or serve, use
meaningful names; see @secref{names}. If you can't come up with a good
name for such pieces, you are probably looking at the wrong kind of
division; consider alternatives.
@; ----------------------------------------------------------------------------- @; -----------------------------------------------------------------------------
@section{Module Interfaces} @section{Module Interfaces}
The purpose of a module is to provide some services. @margin-note{The The purpose of a module is to provide some services.
modules we discuss in this section coincide with files.}
@centerline{Equip a module with a short purpose statement.} @centerline{Equip a module with a short purpose statement.}
@;
Often ``short'' means one line; occasionally you may need several lines.
Its interface describes which services it provides, and its body implements A module's interface describes the services it provides; its body
the services. At least in principle others shouldn't have to read the implements these services. Others have to read the interface if the
implementation ever, but it is quite likely that they have to read the external documentation doesn't suffice:
interface.
@centerline{Place the interface at the top of the module.} @centerline{Place the interface at the top of the module.}
@;
This helps people find the relevant information quickly.
@compare[ @compare[
@;% @;%
@ -33,38 +57,27 @@ Its interface describes which services it provides, and its body implements
(require "game-basics.rkt") (require "game-basics.rkt")
(provide (provide
;; Strtgy = GameState -> Action ;; Stgy = State -> Action
;; Strtgy ;; Stgy
;; a person's strategy ;; people's strategy
human-strategy human-strategy
;; Strtgy ;; Stgy
;; a complete tree traversal ;; complete tree traversal
ai-1-strategy ai-strategy)
;; Strtgy (define (general p)
;; alpha-beta pruning traversal
ai-2-strategy)
;; ------------------------------------------------------------------
(define (general-strategy p)
... ) ... )
;; ------------------------------------------------------------------
... some 100 lines ... ... some 100 lines ...
(define human-strategy (define human-strategy
(general-strategy create-gui)) (general create-gui))
;; ------------------------------------------------------------------
... some 100 lines ... ... some 100 lines ...
(define ai-1-strategy (define ai-strategy
(general-strategy traversal)) (general traversal))))
;; ------------------------------------------------------------------
... some 100 lines ...
(define ai-2-strategy
(general-strategy alpha-beta))))
@(begin @(begin
#reader scribble/comment-reader #reader scribble/comment-reader
(racketmod #:file (racketmod #:file
@ -76,51 +89,36 @@ Its interface describes which services it provides, and its body implements
(require "game-basics.rkt") (require "game-basics.rkt")
;; Strtgy = GameState -> Action ;; Stgy = State -> Action
;; ------------------------------------------------------------------ (define (general p)
(define (general-strategy p)
... ) ... )
... some 100 lines ... ... some 100 lines ...
;; ------------------------------------------------------------------
(provide (provide
;; Strtgy ;; Stgy
;; a person's strategy ;; a person's strategy
human-strategy) human-strategy)
(define human-strategy (define human-strategy
(general-strategy create-gui)) (general create-gui))
... some 100 lines ... ... some 100 lines ...
;; ------------------------------------------------------------------
(provide (provide
;; Strtgy ;; Stgy
;; a complete tree traversal ;; a complete tree traversal
ai-1-strategy) ai-strategy)
(define ai-1-strategy (define ai-strategy
(general-strategy traversal)) (general traversal))
... some 100 lines ... ... some 100 lines ...
))
;; ------------------------------------------------------------------
(provide
;; Strtgy
;; alpha-beta pruning traversal
ai-2-strategy)
(define ai-2-strategy
(general-strategy alpha-beta))))
] ]
As you can see from this comparison, an interface shouldn't just be a As you can see from this comparison, an interface shouldn't just
@scheme[provide] with a list of names. Each identifier should come with a @scheme[provide] a list of names. Each identifier should come with a
purpose statement. purpose statement. Type-like explanations of data also belong into a
@scheme[provide] specification.
@bold{Note} Following this documentation guideline is most applicable to
modules that are a component of a large application. It is less relevant
for a module in the Racket that comes with a full-fledged description in
the guide.
While a one-line purpose statement for a function is usually enough, syntax While a one-line purpose statement for a function is usually enough, syntax
should come with a description of the grammar clause it introduces should come with a description of the grammar clause it introduces
@ -145,10 +143,12 @@ racket
define-strategy) define-strategy)
))] ))]
If the performance of your module doesn't suffer too much from contracts, Consider using @scheme[provide/contract] for module interfaces.
consider using @scheme[provide/contract]. The use of type-like contracts Although contracts affect the performance of your module's services, they
(constructor predicates that check only a tag) impose a tolerable overhead provide a specification and they will help you with the inevitable bug
and still discover simple mistakes. reports you will receive. You should definitely consider type-like
contracts (constructor predicates that check only a tag); they tend to
cost relatively little.
Finally, a module consists of sections. It is good practice to separate the Finally, a module consists of sections. It is good practice to separate the
sections with comment lines. You may want to write down purpose statements sections with comment lines. You may want to write down purpose statements
@ -157,16 +157,9 @@ Finally, a module consists of sections. It is good practice to separate the
chapter headings in DrRacket to label the sections of a module. chapter headings in DrRacket to label the sections of a module.
@; ----------------------------------------------------------------------------- @; -----------------------------------------------------------------------------
@section{Functions & Methods, Classes & Units} @section{Classes & Units}
@; ----------------------------------------------------------------------------- @; -----------------------------------------------------------------------------
@section{Size Matters} @section{Functions & Methods}
Keep functions small. Keep classes small. Keep units small. Keep modules small.
Anytime a unit of code looks incomprehensible, it is probably too
large. Break it up into smaller units. To bring across what these smaller
units compute, implement or serve, use meaningful names; see
@secref{names}. Conversely, if you can't come up with a good name for such
units, you are probably looking at the wrong kind of division; consider
alternatives.