On this page:
6.1 Where to Put Parentheses
6.2 Indentation
6.3 Tabs
6.4 Line Width
6.5 Line Breaks
6.6 Names
6.7 Graphical Syntax
6.8 Spaces
6.9 End of File

6 Textual Matters

Simple textual conventions help eyes find pieces of code quickly. Here are some of those that are easy to check—some automatically and some manually. If you find yourself editing a file that violates some of the constraints below, edit it into the proper shape.

Warning: On rare occasion a unit test may depend on the indentation of a file. This is extremely rare and must be noted at the top so that readers do not accidentally re-indent the file.

6.1 Where to Put Parentheses

Racket isn’t C. Put all closing parentheses on one line, the last line of your code.

good

#lang racket
 
(define (conversion f)
  (* 5/9 (- f 32)))

really bad

#lang racket
(define (conversion f)
  (* 5/9 (- f 32)
    )
  )

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.

acceptable

#lang racket
(define modes
  '(edit
    help
    debug
    test
    trace
    step
    ))

also acceptable

#lang racket
(define turn%
  (class object%
    (init-field state)
 
    (super-new)
 
    (define/public (place where tile)
      (send state where tile))
 
    (define/public (is-placable? place)
      (send state legal? place))
    ))
Doing so is most useful when you expect to add, delete, or swap items in such sequences.

6.2 Indentation

DrRacket indents code and it is the only tool that everyone in PLT agrees on. So use DrRacket’s indentation style. Here is what this means.

For every file in the repository, DrRacket’s "indent all" functions leaves the file alone.

If you prefer to use some other editor (emacs, vi/m, etc), program it so that it follows DrRacket’s indentation style.

Examples:

good

#lang racket
 
; drracket style
(if (positive? (rocket-x r))
    (launch r)
    (redirect (- x)))

bad

#lang racket
 
; .el emacs-file if
(if (positive? (rocket-x r))
    (launch r)
  (redirect (- x)))

Caveat 1: Until language specifications come with fixed indentation rules, we need to use the default settings of DrRacket’s indentation for this rule to make sense. If you add new constructs, say a for loop, please contact Robby for advice on how to add a default setting for the indentation functionality. If you add entire languages, say something on the order of Typed Racket, see DrRacket support for #lang-based Languages for how to implement tabbing.

Caveat 2: This rule does not apply to scribble code.

6.3 Tabs

Do not use tab characters in your code. Tabs make it hard to use textual tools like git or diff effectively. To disable tabs,
  • in DrRacket: you are all set. It doesn’t insert tabs.

  • in Emacs: add (setq indent-tabs-mode nil) to your emacs initialization file.

  • in vi: :set expandtab1.

6.4 Line Width

A line in a Racket file is at most 102 characters wide.

If you prefer a narrower width than 102, and if you stick to this width “religiously,” add a note to the top of the file—right below the purpose statement—that nobody should violate your file-local rule.

This number is a compromise. People used to recommend a line width of 80 or 72 column. The number is a historical artifact. It is also a good number for several different reasons: printing code in text mode, displaying code at reasonable font sizes, comparing several different pieces of code on a monitor, and possibly more. So age doesn’t make it incorrect. We regularly read code on monitors that accommodate close to 250 columns, and on occasion, our monitors are even wider. It is time to allow for somewhat more width in exchange for meaningful identifiers.

So, when you create a file, add a line with ;;  followed by ctrl-U 99 and -. When you separate "sections" of code in a file, insert the same line. These lines help both writers and readers to orient themselves in a file. In scribble use @;  as the prefix.

6.5 Line Breaks

Next to indentation, proper line breaks are critical.

For an if expression, put each alternative on a separate line.

good

#lang racket
 
(if (positive? x)
    (launch r)
    (redirect (- x)))

bad

#lang racket
 
(if (positive? x) (launch r)
    (redirect (- x)))

It is acceptable to have an entire if expressions on one line if it fits within the specified line width (102):

also good

#lang racket
 
(if (positive? x) x (- x))

Each definition and each local definition deserves at least one line.

good

#lang racket
 
(define (launch x)
  (define w 9)
  (define h 33)
  ...)

bad

#lang racket
 
(define (launch x)
  (define w 9) (define h 33)
  ...)

All of the arguments to a function belong on a single line unless the line becomes too long, in which case you want to put each argument expression on its own line

good

#lang racket
 
(place-image img 10 10 background)
 
; and
 
(above img
       (- width  hdelta)
       (- height vdelta)
       bg)

bad

#lang racket
 
(above ufo
       10 v-delta bg)

Here is an exception:

good

#lang racket
 
(overlay/offset (rectangle 100 10 "solid" "blue")
                10 10
                (rectangle 10 100 "solid" "red"))
In this case, the two arguments on line 2 are both conceptually related and short.

6.6 Names

Use meaningful names. The Lisp convention is to use full English words separated by dashes. Racket code benefits from the same convention.

good

#lang racket
 
render-game-state
 
send-message-to-client
 
traverse-forest

bad

#lang racket
 
rndr-st
 
sendMessageToClient
 
traverse_forest
Note that _ (the underline character) is also classified as bad Racketeering within names. It is an acceptable placeholder in syntax patterns, match patterns, and parameters that don’t matter.

Another widely used convention is to prefix a function name with the data type of the main argument. This convention generalizes the selector-style naming scheme of struct.

good

#lang racket
 
board-free-spaces      board-closed-spaces    board-serialize
In contrast, variables use a suffix that indicates their type:

good

#lang racket
 
(define (win-or-lose? game-state)
  (define position-nat-nat (game-state-position game-state))
  (define health-level-nat (game-state-health game-state))
  (define name-string      (game-state-name game-state))
  (define name-symbol      (string->symbol name-string))
  ...)
The convention is particularly helpful when the same piece of data shows up in different guises, say, symbols and strings.

Names are bad if they heavily depend on knowledge about the context of the code. It prevents readers from understanding a piece of functionality at an approximate level without also reading large chunks of the surrounding and code.

Finally, in addition to regular alphanumeric characters, Racketeers use a few special characters by convention, and these characters indicate something about the name:

Character

Kind

Example

?

predicates and boolean-valued functions

boolean?

!

setters and field mutators

set!

%

classes

game-state%

<%>

interfaces

dc<%>

^

unit signatures

game-context^

@

units

testing-context@

#%

kernel identifiers

#%app

Identifiers with this prefix are mostly used in modules that define new languages. The use of #% to prefix names from the kernel language warns readers that these identifiers are extremely special and they need to watch out for subtleties. No other identifiers start with # and, in particular, all tokens starting with #: are keywords.

6.7 Graphical Syntax

Do not use graphical syntax (comment boxes, XML boxes, etc).

The use of graphical syntax makes it impossible to read files in alternative editors. It also messes up some revision control systems. When we figure out how to save such files in an editor-compatible way, we may relax this constraint.

6.8 Spaces

Don’t pollute your code with spaces at the end of lines.

If you find yourself breaking long blocks of code with blank lines to aid readability, consider refactoring your program to introduce auxiliary functions so that you can shorten these long blocks of code. If nothing else helps, consider using (potentially) empty comment lines.

6.9 End of File

End files with a newline.