Why Heroes

· rebel rebel

Heroes starts with two constraints: the code must be easy for a model to read, and programs must be able to use C libraries.

Recurring model mistakes · sound and vision

Models that generate code make recurring mistakes: they swap arguments of the same type, forget a case, use an undeclared name or borrow a keyword from another language. Heroes is designed to let the compiler catch these mistakes.

A language designed so that every plausible LLM mistake is a compile error will produce working programs in fewer total tokens than a conventional language, even if each program costs more tokens to write.

One part of the thesis has been tested by introducing plausible mistakes into working programs and counting those the compiler catches. The same programs are then checked with the Heroes-specific rules disabled. The comparison measures the effect of those checks. The total token savings still need to be measured. Tokens are the pieces of text a model reads and generates. The test results → What is measured, what was written down before measuring, and what is not known yet →

Why avoiding errors can save tokens

real cost = program tokens × (1 + rewrite rate)

Shorter syntax reduces the tokens needed to write a file. Fixing an error requires more steps: the model reads the message, rereads the code, rewrites a function and tries compiling again. Avoiding a correction can therefore save more tokens than shorter syntax.

Heroes therefore uses explicit declarations and short forms for common operations. It requires extra words where they help the compiler recognise a mistake.

Using existing libraries

Heroes uses C libraries for files, sockets, databases and graphics. Developing and maintaining its own libraries would require too much work for a project run by one person. Heroes provides the essential operations and uses existing C libraries for the rest.

maths beyond arithmetic    →  libm          files, sockets   →  libc
regular expressions        →  PCRE2         HTTP             →  libcurl
JSON                       →  cJSON         SQL              →  SQLite
graphics, audio, terminal  →  SDL, raylib, ncurses

To use a library, declare the functions you need. The name on the first line identifies the header, the file that describes the library’s functions and types. Clang, the C compiler, checks your declarations against that file.

extern "math.h" link "m"
    function sqrt(x: f64) -> f64
    function pow(base: f64, exponent: f64) -> f64
    function floor(x: f64) -> f64
examples/gallery/08-ffi.hero, lines 12–15

A person or model might declare a C function that does not exist. The compiler catches this too by checking the library’s header:

error[ffi_unknown_name]: `math.h` declares no `sqrtt` — clang read the header and could not find it
  at ffi-demo.hero:2:5
    |
  2 |     function sqrtt(x: f64) -> f64
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  note: an `extern` names what the header already has (§4.19): check the spelling, or name the header that does declare `sqrtt`

Clang uses the library’s actual header. It checks names and type widths where required, reporting errors before the program runs. Heroes does not need to maintain a second description of the library.

The header makes it possible to check the declarations. Heroes’ own rules still apply: pow(base:, exponent:) takes two values of the same type, so the call must name its arguments.

The available operations include print, len, push, slice, sort, conversions between types, map, filter and fold. Every addition requires a recorded decision.

Using C libraries should be as straightforward as writing Heroes code. When a library cannot be used from Heroes, the programmer has to write more C code. The project aims to reduce that need. Programs that use C libraries →

Why the compiler emits C

Heroes translates your program into C and lets clang produce the executable. This lets clang check the C function declarations against the libraries’ headers on every build. The initial plan was to generate machine code directly; it changed to make use of these checks. Library verification, rather than a speed advantage, drove the choice.

Seven words can begin a line

A file is a list of declarations, each starting with the word for what it declares. constant for a fixed value, function, record for a group of named fields, variant for a value that comes in several forms. Three more declare nothing about your data: use for another file, test, and extern for what comes from C. The list ends there. No classes, no interfaces, and nowhere a global variable anybody can modify.

# A position on the integer grid.
record Point
    x: i64
    y: i64

# A rectangle, by two corners.
record Rect
    corner: Point
    extent: Point
examples/gallery/01-points.hero, lines 6–14

You can write declarations in any order. Two functions can call each other without forward declarations. During compilation, Heroes reduces the code to seven constructs, the basic internal forms used to represent a program.

Why strings have holes

A string can carry values, and an f before the opening quote is what turns {n} into the text of n.

function line(at: i64, of: i64, star: Star) -> str
    return f"{at}/{of} {star.name} at magnitude {star.magnitude}"
examples/gallery/12-interpolation.hero, lines 20–21

Why the f: a brace already had a job inside plain strings, and over two hundred of the compiler’s own strings carried one, so a string that reads holes announces it at its first character and every other string is unchanged. Why any expression: listing the admitted forms cost more specification tokens than admitting them all, and the count decided. What a hole may hold, what {{ writes, and what the compiler says to a hole with no text are in the chapter. Strings, holes included → The whole example →

The language rules · fashion

What Heroes is bad at

Each one is a choice, and this is what it costs.

Common questions · quicksand, avoided

Why no null, why named arguments, why every assignment is a copy, how fast it is, what it costs, whether to trust a compiler an AI writes: the questions people ask before trying Heroes have a page of their own, each answered in a few lines. Common questions →

To continue: The whole language is one file, small enough to hand to a model with room left for your program. Every program in the repository is written in it, and four commands build the compiler.