What a style guide is
Think of a classroom where everyone keeps notes in the same way: the date in the top corner, headings underlined, one idea per line. None of that changes what the notes say. It means you can pick up a friend’s notebook and find your way around it at once.
A style guide does the same for code. The compiler does not care whether you indent with two spaces or eight, or whether a function is called TotalPrice or total_price. People do. Code is read many more times than it is written, and most of those reads are by someone who did not write it, including you, six months later.
Here is one program written twice. Both compile and both print 12.
fn area(width: int, height: int): int { return width * height;}fn main(): int { immut w: int = 3; immut h: int = 4; printline(area(w, h)); return 0;}fn AREA(W:int,H:int):int{return W*H;}fn main():int{immut a:int=3;immut B:int=4;printline(AREA(a,B));return 0;}The second one works. It is just tiring to read, and every reader pays that cost again.
Three documents, three jobs
Turf has three kinds of official writing. It helps to know which one answers which question.
- What is allowedLanguage reference
What a program means and what the compiler accepts. Break it and the program does not compile.
- How to write it wellStyle guide
This guide. How readable, idiomatic Turf is written. Break it and the program still works.
- How Turf changesDesign proposals
How a new feature is proposed, argued over and accepted, and why.
How to read a rule
Every rule in the guide has the same four parts:
- A number, such as
TSG-101. The number never changes and is never reused for another rule, so you can quote it in a code review, a commit message or a diagnostic and it always means the same thing. - A level.
- Required means everyone follows it, and a tool will eventually check it for you.
- Recommended means it is good advice, and you can break it when you have a reason.
- Which tool checks it, if any. Today only
turf fmtchecks anything, and only four rules. - Two examples: one to copy (Do) and one to avoid (Don’t). Both are real programs, and both compile.
The first digit of the number tells you which page the rule is on:
| Numbers | Page | What it covers |
|---|---|---|
TSG-1xx |
Indentation | spaces, blank lines, line length |
TSG-2xx |
Identifier naming | what to call things |
TSG-3xx |
Import organization | file names, imports and the order of a file |
TSG-4xx |
Function and type formatting | braces, spacing, lists and compare |
TSG-5xx |
Error-handling conventions | !T, panics and error messages |
TSG-6xx |
Public API documentation | comments and pub |
TSG-7xx |
Idiomatic Turf | which form to pick when there are several |
TSG-8xx |
Safety | unsafe, C code and resources |
Where the guide is going
The guide is new. It is written now, it grows and settles during Turf 2.x, and at Turf 3.0 the formatter learns it.
- Nowthe rules are written down and discussed
- Turf 2.xrules are added, argued over and settled
- Before 3.0the formatting rules are frozen
- Turf 3.0
turf fmtapplies every required formatting rule
- Until 3.0,
turf fmtdoes not change. It keeps doing exactly the four things it does today (TSG-101 to TSG-104), so the formatter’s output stays the same across every 2.x release while the guide is still moving. - Before 3.0, any rule can still change. No tool enforces the new rules yet, so changing one breaks nobody’s build.
- At 3.0, the formatting rules are frozen and
turf fmtis updated to apply them, all at once. A project adopts them by runningturf fmt --writeone time. - After 3.0, a new formatting rule lands in this guide and in
turf fmttogether, and a rule that changes whatturf fmtoutputs is listed in the release notes.
All rules at a glance
| Rule | In short | Level | Checked by |
|---|---|---|---|
| TSG-101 | Indent with four spaces | Required | turf fmt |
| TSG-102 | No spaces at the end of a line | Required | turf fmt |
| TSG-103 | Never more than one blank line in a row | Required | turf fmt |
| TSG-104 | End every file with one newline | Required | turf fmt |
| TSG-105 | Keep lines to 100 characters | Recommended | none yet |
| TSG-201 | Values and functions are snake_case | Required | none yet |
| TSG-202 | Types and variants are PascalCase | Required | none yet |
| TSG-203 | Constants are UPPER_CASE | Required | none yet |
| TSG-204 | Type parameters are single capital letters | Recommended | none yet |
| TSG-205 | A bool reads as a yes-or-no question | Recommended | none yet |
| TSG-206 | Spell names out | Recommended | none yet |
| TSG-207 | A recoverable twin starts with try_ | Recommended | none yet |
| TSG-301 | Files are named in snake_case | Required | none yet |
| TSG-302 | Imports go at the top, in groups | Recommended | none yet |
| TSG-303 | Do not import the prelude | Recommended | none yet |
| TSG-304 | Put things in a file in a fixed order | Recommended | none yet |
| TSG-401 | Opening braces go on the same line | Recommended | none yet |
| TSG-402 | No brackets around a condition | Recommended | none yet |
| TSG-403 | Spaces around operators and after commas | Recommended | none yet |
| TSG-404 | Trailing comma on the last line of a list | Recommended | none yet |
| TSG-405 | Lay out compare arms on their own lines | Recommended | none yet |
| TSG-501 | Pick the failure shape by why it fails | Recommended | none yet |
| TSG-502 | Say what failed in the error message | Recommended | none yet |
| TSG-503 | Never hide a failure that matters | Recommended | none yet |
| TSG-601 | Write // comments with one space after the slashes | Recommended | none yet |
| TSG-602 | Say why, not what | Recommended | none yet |
| TSG-603 | Describe the code as it is now | Recommended | none yet |
| TSG-604 | Comment every pub item | Recommended | none yet |
| TSG-605 | Make pub only what other files need | Recommended | none yet |
| TSG-701 | Use immut unless the value changes | Recommended | none yet |
| TSG-702 | Write mut and immut, not mutable and immutable | Recommended | none yet |
| TSG-703 | Write the type unless the value makes it obvious | Recommended | none yet |
| TSG-704 | Use the short forms for counting | Recommended | none yet |
| TSG-705 | Count with for, not while | Recommended | none yet |
| TSG-706 | One give / otherwise per expression | Recommended | none yet |
| TSG-707 | Name every variant when you compare an enum | Recommended | none yet |
| TSG-708 | Keep main short | Recommended | none yet |
| TSG-801 | Keep unsafe blocks small | Recommended | none yet |
| TSG-802 | Wrap C functions in a Turf function | Recommended | none yet |
| TSG-803 | Use &T unless nothing is a real answer | Recommended | none yet |
| TSG-804 | Close a resource with defer, on the next line | Recommended | none yet |
Changing the guide
The guide belongs to everyone who writes Turf. To suggest a new rule or argue against one, open an issue on turf-lang/turf-lang or comment on turf-lang#281. A good suggestion says which rule, what should change, and shows a short piece of real code where the change helps.
Rules are changed carefully, not on a timetable:
- A settled rule stays settled unless there is a strong reason to change it.
- New syntax gets its rules in the same release that ships it, never before.
- A rule that is removed keeps its number, marked as withdrawn, so old references still lead somewhere.
Changelog
| Date | Change |
|---|---|
| 19 October 2026 | First draft: 41 rules in six areas. |