AXIOM 0: 0-indexed > N-indexed

The rationale comes from basic group theory. Indices are more often treated as elements of an additive group than a multiplicative one. I.e. indices are more often added than they are multiplied, so it is natural for the base index to be the additive unit, namely .

ref. dynamic programming algorithms that build up a solution using arrays, where the inductive base case often naturally corresponds to zero.

AXIOM 1: AST macros > templates > language syntax

Examples of languages that do it right: Nim, Scheme.

Rust is an example of a language that tried to do the right thing, but failed horribly at it. Its AST macro system is pathetically gimped and cowardly.

Programming languages that did not adopted an ethos of meta-programming or AST manipulation early on have all invariably end up feeling extremely stale and static (e.g. Java).

Imagine a puzzle game: the language in which you can easily work with widgets, manipulate stateful UI changes, animations, etc. on the front-end side probably loses a lot of its naturality in the back-end when you try to express the game rules in a logical declarative way.

Different problems are usually solved using different languages, so a language in which you can program the language itself is inherently more versatile and has a wider scope than a static language without any meta-programming capabilities.

Yet modern languages like Go and Dart purposefully break from this axiom, chasing the success trajectory of C, Java, et cetera.

In static languages new features must be constantly added to improve ergonomics:

  • Good news! We’ve added a special short-hand syntax to the for-loop statement for iterating over arrays!
  • Good news! You can now implement custom iterable types that can be used in for-loops!
  • Good news! For loops now have optional syntax to make the index available during its scope.
  • Good news! We’ve added a special syntax for using for-loops as an inline expressions which evaluate to arrays.
  • Good news! You can now collect expression-for-loops into custom data structures that implement interface so-and-so!
  • Good news! We’ve now added special syntax support for writing generator functions that compile into regular for-loops!
  • … and so on.

Some languages end up adding a ton of such special cases or additional syntax, almost all of which could have been made as user-land macros or user-controllable libraries if the language had a non-static parsing process in mind from the start.

Some static languages get extremely far with no AST macros, though, especially untyped languages or well-designed functional languages. Notable examples here are Python and Haskell. The former usually has excellent meta-programming capabilities through run-time reflection, and the latter is hard carried by the functional programming paradigm’s emphasis on raw expressive power.

AXIOM 2: 0-cost >= safety


AXIOM 3: expressions > statements

Or: why functional gets so many things for free.


AXIOM 4: integrated build system > third-party


Note: see about Zig’s zig build.

AXIOM 5: libgmp > homemade bigints

People need to stop rolling their own arbitrary precision integers.

Integers are extremely important, and they need to be extremely efficient. No language that rolls their own toy big-integers has even gotten close to par with GMP. (C.f. Python.)

AXIOM 6: type classes > object-oriented


AXIOM 7: algebraic pattern matching > if-chains or switch-statements

TODO: should be obvious.

AXIOM 8: cohesion > gimmicks > pandering