Format Checker
Programs are meant to be read by humans and only incidentally for computers to execute.
— H. Abelson and G. Sussman
Structure and Interpretation of Computer Programs
Background
Most programming languages promote a uniform coding style, either with a style guide (e.g. Python’s PEP 8) or with formatting utilities (aka “linters”).
THT goes a step further by having a Format Checker that identifies issues at compile time.
The rules are taken from two main sources:
- Convention. Rules curated from the most popular style guides for PHP and comparable languages (e.g. Java & JavaScript).
- Basic typographic rules for legibility
Benefits of Built-In Code Formatting
- Consistent code is easier to read & understand.
- Clean code is more enjoyable to work with.
- Clean code is less prone to errors.
- Collaboration and sharing of code is easier.
- Novices will learn best practices quicker.
- Teams will spend less time debating what rules to follow.
- No need to set up a separate “linter” build step.
Q: Why is whitespace so important?
Consistent use of whitespace creates a visual rhythm, and follows our natural ability to visually process information in chunks that are related to each other (see “Gestalt laws of grouping”).
Using conventions frees your brain from the mundane aspects of programming, which offer little payback.
— Steve McConnell, Code Complete
Formatting Rules
General
- No lines over 120 characters long. This does not apply to multi-line strings and template functions.
- UNIX newlines. Line endings should be set to
LF
(UNIX). NotCRLF
(Windows). - UTF-8. Files should be saved as UTF-8 encoded.
Indent With Spaces
TAB characters are not allowed.
Configure your editor to insert 4 spaces for your Tab key (aka “soft tabs”), if it doesn’t already do so by default.
Whitespace
Indentation
Lines inside multiline braces of {}
, []
, or ()
should be indented 4 spaces.
// ✓ Yes if true { print('...') } // ✕ No if true { print('...') } // ✓ Yes $list = [ 111 222 333 ] // ✕ No $list = [ 111 222 333 ]
Infix operators + = == &&
Space before & after: YES
$a = $b + 1 // ✓ Yes $a = $b+1 // ✕ No $a=$b+1 // ✕ No if $isGood && $isOk {...} // ✓ Yes if $isGood&&$isOk {...} // ✕ No
Prefix operators ! -
Space after: NO
if !$isAdmin {...} // ✓ Yes if ! $isAdmin {...} // ✕ No $a = -23 // ✓ Yes $a = - 23 // ✕ No
Commas ,
Space before: NO
Space after: YES
doSomething($a, $b, $c) // ✓ Yes doSomething($a,$b,$c) // ✕ No
Parentheses ( )
Inside padding: NO
Outer wrapping: NO
doSomething($myVar) // ✓ Yes doSomething( $myVar ) // ✕ No $a = $b / ($c / $d) // ✓ Yes $a = $b / ( $c / $d ) // ✕ No
Square Braces [ ]
Inside padding: NO
$a = [1, 2, 3] // ✓ Yes $a = [ 1, 2, 3 ] // ✕ No $user['userId'] // ✓ Yes $user[ 'userId' ] // ✕ No
Curly Braces { }
Inside padding: YES
$a = { foo: 1 } // ✓ Yes $a = {foo: 1} // ✕ No if $isOk { return $a } // ✓ Yes if $isOk {return $a} // ✕ No
Colons :
Space before: NO
Space after: YES
$a = { foo: 1 } // ✓ Yes $a = { foo : 1 } // ✕ No ^ $a = { foo:1 } // ✕ No ^^
Function Argument List ( )
Space before: NO
Space after: YES
fun foo($myVar) { // ✓ Yes fun foo($myVar){ // ✕ No ^^ fun foo ($myVar) { // ✕ No ^
Open Braces {
Space before: YES
Same line: YES
// ✓ Yes fun main { // ✕ No fun main{ // ✕ No fun main {
Closing Braces } ]
Next Line: YES
// ✓ Yes $nums = [ 111 222 ] // ✕ No $nums = [ 111 222 ]
Trailing Commas ,
After single line: NO
After multiple lines: NO
// ✕ No $list = [1, 2, 3, ] ^ // ✕ No $map = { aa: 1, bb: 2, cc: 3, } ^ // ✕ No $map = { aa: 1, bb: 2, cc: 3, } // ✓ Yes $map = { aa: 1 bb: 2 cc: 3 } // ✓ Yes $list = [ 111 222 333 ]
Blank Lines
Use blank lines to group related lines together. Think of consecutive line of code as a “paragraph”.
// ✕ No $userName = getUserName() if $userName == 'admin': return true $userAgeDays = getUserAgeDays($userName) if $userAgeDays > 1000: return true // ✓ Yes $userName = getUserName() if $userName == 'admin': return true $userAgeDays = getUserAgeDays($userName) if $userAgeDays > 1000: return true
Parser Rules
Names
Module and class names are strict UpperCamelCase. This includes acronyms.
User XmlReader XmlHttpRequest
All other names (variables, functions, bare map keys) are strict camelCase. This includes acronyms.
user firstName userId userHasIphone httpOutput
Other Rules
Assignment inside conditional: NO
// ✕ No if $line = readLine() {...} ^ // ✓ Yes (If-Assign operator) if $line := readLine() {...} ^^
Nested ternary expressions: NO
// ✕ No check1 ? action1() : check2 ? action2() : action3() // ✓ Yes - if/else if check1 { action1() } else if check2 { action2() } else { action3() }
Max function arguments: 4
Use Option Maps for keyword arguments.
// ✕ No - More than 4 arguments fun doSomething($a1, $a2, $a3, $a4, $a5) { ... } // ✓ Yes - Combine args into a Map doSomething('foo', { flag: true, num: 123 }) fun doSomething($mainArg, $args) { $args.check({ flag: false num: 0 }) }
HTML Templates
These are additional rules for markup within HTML Template Functions.
Tag Names
Uppercase: NO
// ✕ No <SPAN> // ✓ Yes <span>
Parameters
Quoted: YES
// ✕ No <div class=my-class> // ✓ Yes <div class="my-class">
Space around equals: NO
// ✕ No <div class = "my-class"> // ✓ Yes <div class="my-class">