What you learn by making a new programming language

Creating your own programming language is framed as a highly educational, if quixotic, project that deepens understanding of parsing, type systems, runtimes, and the tradeoffs behind existing languages and DSLs. Commenters share experiences ranging from toy compilers and esoteric languages to serious efforts like configuration languages, proof assistants, and Lisp/Forth variants, noting how easily “config” or JSON-based systems evolve into unintended interpreters. While many caution that such side projects can consume time better spent on applications, others argue the insight and creative satisfaction gained make the effort worthwhile even if the resulting language is incomplete or impractical.

Value and goals of making a language

  • Many commenters say implementing a language or compiler was one of their most educational experiences.
  • It deepens understanding of parsing, type systems, runtimes, and how high-level constructs map to lower-level execution.
  • Several people built toy languages (often for fun or a class) and report lasting intuition gains, even if the language is now obsolete.
  • Others use language projects as a way to stay mentally flexible and avoid being “the person who only does one app.”

Complexity, grammar, and tooling

  • Strong advice to start with an extremely simple grammar; complexity explodes quickly.
  • One rule-of-thumb: difficulty grows roughly with the square of the number of grammar rules.
  • Some recommend Lisp-like syntaxes because s-expressions are trivial to parse and let you focus on semantics.
  • Others suggest skipping a custom parser at first: express ASTs in JSON/YAML/TOML, then add real syntax later.
  • Parser generators (ANTLR, JavaCC, yacc) and tools like Tree-sitter are praised for reducing friction.
  • Writing a debugger early is recommended; you will need it.

DSLs, configuration, and “oops, I made an interpreter”

  • Recurrent story: a config format gains variables, conditionals, loops, then becomes a de facto programming language.
  • This is linked to Greenspun’s rule: complex systems in low-level languages tend to reimplement higher-level language features.
  • Some argue data and execution should stay separate; mixing them makes data hard to inspect and systems harder to reason about.
  • Others say once users want loops, you should embed a real language (Lua, Lisp, JS, Starlark) rather than grow an awkward DSL.
  • Debate over whether config languages should be Turing-complete; both sides exist, with examples of rich tooling on each.
  • There’s tension between having one general-purpose language for both code and config vs. a specialized configuration language.

Lisp, usability, and semantics

  • Discussion around whether Lisp is only suitable for “high-IQ” users or is actually quite simple once prefix notation is learned.
  • Several claim Lisp’s fully parenthesized syntax is easy and that real difficulty lies in language semantics, not surface syntax.

Skepticism, opportunity cost, and anecdotes

  • Some push back: with limited time, a personal language may be too buggy and incomplete to be worth it, compared to using mature tools.
  • One analogy: spending years building a custom synth and then losing interest in making music.
  • Others counter that the educational value and joy are sufficient justification, even if the result is “a bad language.”

Resources and examples

  • Numerous links to personal languages, esoteric interpreters (e.g., Brainfuck, Forth), proof assistants, and a type-theory textbook are shared as inspiration.