Skip to content
📖 Auto vs Modern CBook contents

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.

c
// 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.

c
// 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.

c
// 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
// 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:

EntityConventionExample
Variablessnake_casebuffer_size, row_count
Functionssnake_casecompute_area, parse_int
Type namesPascalCaseTreeNode, FileHandle
Macros/ConstantsUPPER_SNAKE_CASEMAX_SIZE, PI
Struct memberssnake_casefirst_name, age

Descriptive names. A name should convey what something is or does:

c
// 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:

auto
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.

Released under the MIT License.