Chapter 9: Style
Level 2 — Cognition
Writing code that humans can read: formatting, naming, and internationalization.
Code is read far more often than it is written. Style is not cosmetic -- it is engineering discipline that reduces bugs, accelerates review, and makes maintenance possible. This chapter covers the conventions that C programmers have developed over five decades and how Auto encodes many of them into the language itself.
9.1 Formatting
Consistent formatting is the single easiest improvement you can make to a codebase. The C community has converged on several widely accepted rules:
Indentation. Use either 4 spaces or tabs consistently throughout a project. Never mix them. Most modern C projects prefer 4-space indentation.
// Good: consistent 4-space indent
if (x > 0) {
for (int i = 0; i < x; i++) {
printf("%d\n", i);
}
}
// Bad: mixed indentation
if (x > 0) {
for (int i = 0; i < x; i++) {
printf("%d\n", i);
}
}Line length. Keep lines under 80 characters. Long lines indicate overly complex expressions that should be broken up.
// Good: broken across lines
int result = compute_something(
input_data,
buffer_size,
&output_count
);
// Bad: excessively long line
int result = compute_something(input_data, buffer_size, &output_count);Brace style. The two dominant styles in C are K&R (opening brace on the same line) and Allman (opening brace on its own line). Pick one and be consistent.
// K&R style (most common in C)
if (condition) {
do_something();
}
// Allman style
if (condition)
{
do_something();
}Auto uses K&R style by default and enforces it with auto fmt:
// Auto enforces consistent formatting
fn calculate_area(width float, height float) float {
width * height
}Running auto fmt on a project reformats every file to a single canonical style, eliminating formatting debates entirely.
Takeaway: Consistency matters more than any particular style choice. If your project has a convention, follow it. If not, adopt
auto fmt.
9.2 Naming
Names are the primary documentation of intent. Well-chosen names make code self-explanatory; poorly chosen names create confusion.
C naming conventions:
| Entity | Convention | Example |
|---|---|---|
| Variables | snake_case | buffer_size, row_count |
| Functions | snake_case | compute_area, parse_int |
| Type names | PascalCase | TreeNode, FileHandle |
| Macros/Constants | UPPER_SNAKE_CASE | MAX_SIZE, PI |
| Struct members | snake_case | first_name, age |
Descriptive names. A name should convey what something is or does:
// Good: descriptive names
int student_count = 0;
float average_grade = 0.0f;
const char* output_filename = "result.txt";
// Bad: cryptic abbreviations
int sc = 0;
float ag = 0.0f;
const char* ofn = "result.txt";Auto naming conventions. Auto uses snake_case for functions and variables, PascalCase for types, and associates functions with types using dot notation:
type Rectangle {
width float
height float
}
fn Rectangle.area(r Rectangle) float {
r.width * r.height
}
fn main() {
let rect Rectangle = Rectangle(5.0, 3.0)
print("Area:", rect.area(rect))
}The key advantage of Auto's naming system is that associated functions (Rectangle.area) are discoverable -- the type name acts as a namespace. In C, you must rely on naming conventions (rectangle_area) to achieve the same clarity.