Syntax with Purpose in a Programming Language

Lobsters Hottest News

Summary

This article explores the importance of syntax design in programming languages, arguing that syntax should accurately reflect the language's computational model and mental model, rather than being arbitrarily cobbled together for familiarity or conciseness. The author analyzes the syntax design of OCaml, Lisp/Clojure, and JavaScript, and introduces his own language Saul, emphasizing uniformity and semantic consistency.

<p><a href="https://lobste.rs/s/bovmc5/syntax_with_purpose_programming">Comments</a></p>
Original Article
View Cached Full Text

Cached at: 07/13/26, 01:53 PM

TL;DR: The syntax of a programming language is not arbitrary; it should accurately reflect the underlying computational model and mental model of the language, rather than being a hodgepodge of convenience for "familiarity" or "saving keystrokes." ## The Real Role of Syntax Many people treat programming language syntax as a bag of random features thrown in to reduce typing or "provide expressiveness"—like Python's "The Zen of Python" says "Write less." But there's no guarantee; good or bad syntax design directly determines whether a language can clearly express intent. I am in the process of rewriting a C++ database kernel in OCaml, and during this process I have deeply felt the impact of syntax on mental models. ## OCaml's `let in`: Nesting and Scope In OCaml (and other languages in the ML family), `let in` is an expression: you first give a variable a name and a value, then the expression after `in` is evaluated under that binding. This is different from variable assignment in C. Variables in C are more like "names for memory boxes," while `let in` is closer to substitution in lambda calculus—no assignment, just replacing names with the corresponding expressions. ```ocaml let x = 1 in let y = x + 2 in y * 3 ``` You can nest these bindings like nested functions; it's essentially currying. The key point is that **syntax should tell you what you are doing**. At the module level, OCaml also uses `let` but without `in`, because the evaluation ends at the module rather than the next inner expression. Inside a function, you see `in` to separate different scopes. This subtle syntactic difference reflects a difference in language semantics—the former is "define at module scope," the latter is "locally bind in an expression and continue evaluation." ## Lisp and Clojure: Consistent List and Vector Syntax In Lisp, `let` is used for local bindings: ```elisp (let ((b 2)) (+ a b)) ``` Here you see a list of lists: the outer `let` expression is a list, its first sublist is the binding list, and each binding is a two-element list (variable name and value). The structure is very consistent: you only need to understand the "list" data structure, and then `let` interprets it in a specific way. Clojure uses vectors for the same effect: ```clojure (let [b 2] (+ a b)) ``` Here it uses a vector `[b 2]` instead of a list of lists. But the reader interprets it the same way: taking elements in pairs as (value, label). In fact, Clojure also allows map form (`{key value}`) for bindings, but the reader ignores commas. Whichever notation, the core idea is the same: **the language provides a unified element (list, vector, map), and then in different contexts (like `let`, `fn`, `cond`), it parses it with the same set of rules**. This consistency reduces cognitive load. ## JavaScript's Syntax Disaster JavaScript's syntax is absolutely terrible. It was supposed to be a Scheme (an interactive, Lisp-like language), but because Java and C were popular in the 90s, it was forcibly changed to a C-like syntax for "familiarity." The result is that it tries to represent what it is not. This "familiarity" is an argument for "worse is better." JavaScript's syntax lacks a unified underlying semantic support and is full of historical legacy special rules and edge cases. ## My Language Saul: Unified Design I am writing a language called Saul, which is a total Turing-incomplete language guaranteeing the totality property (all functions terminate). This is important in database design because languages like PL/pgSQL that allow arbitrary recursion are a giant footgun. Saul's syntax is inspired by Prolog and Smalltalk, striving for uniformity. For example, the notation for relations: ```saul integer(42) % 42 is associated with the integer relation person("Alice") % string bound to person plus(1, 2, 3) % plus relation, similar to a function ``` The idea is: **the entire language syntax has only one core construct—relations**. Variables, functions, and types are all expressed uniformly within this framework. This is better than OCaml's approach of "sacrificing uniformity for brevity." OCaml was originally targeting .NET and later became an independent language, which has fragmented its syntax: you can still type certain ancient keywords, but the formatter removes them, ending up looking like you are doing a loose double binding that confuses two fundamentally different things. ## Conclusion: Syntax Design Is Not Arbitrary The specification of syntax must serve the mental model of the language. When you write code in a language, you are in a specific mode of thinking. What's good about Lisp is that you can change the way of handling problems at any time (macros), while for most languages, you can only use the limited abstractions provided by the language. Behind these abstractions there should be a motivation, not a casual creation to justify a special rule or make novices "feel familiar." If the syntax cannot clearly tell you what each statement represents, cannot express the operation of an evaluated term under a closed-world assumption, then it is bad design. This is by no means a trivial complaint. Even though it really gets on my nerves. Source: https://www.youtube.com/watch?v=_HLZoeFREFo

Similar Articles

Stroustrup's Rule (2024)

Hacker News Top

Bjarne Stroustrup's rule states that for new features, programmers prefer explicit syntax, but once established, they prefer terse notation. The article explores examples in Rust and Python and discusses implications for language design and teaching.

Designing Lispy DSLs, part 1: SCSS (2012)

Lobsters Hottest

This article explores the design of Lispy domain-specific languages using SCSS, a Scheme-based CSS preprocessor, as a case study. It discusses how SCSS represents CSS as first-class values and the limitations of its implementation.

@123olp: Programming Mindset ├── 0. Core Definition │ ├── Turn fuzzy problems into computable problems │ ├── Turn real-world objects into data representations │ ├── Turn the solution process into clear steps │ ├── Turn results into verifiable outputs │ └── Turn one-time solutions into reusable systems │ ├──…

X AI KOLs Timeline

A systematic tutorial on programming mindset, covering core definitions, problem modeling, data representation, process design, and multiple aspects of learning programming.

Towards Understandable Software

Lobsters Hottest

The article critiques current programming practices and the reliance on LLMs, arguing instead for better abstraction, documentation, and software stacks to make code more understandable and maintainable.