Topic domain
Programming Languages
Semantics, type systems, and the design space of notation.
- Articles
- 80
- Clusters
- 8
- Foundational
- 24
- Intermediate
- 32
- Advanced
- 24
Syntax, ergonomics, and feature interactions.
- Automatic Semicolon Insertion and Restricted Productions
- The Dangling Else and How Grammars Resolve Ambiguity
- Operator Precedence Tables and Why They Are a Design Artifact
- Evaluation Order, Sequencing Points, and Unspecified Behaviour
- Short-Circuit Evaluation as a Language Guarantee
- Pattern Matching and the Exhaustiveness Check
Type Systems
10Inference, subtyping, polymorphism, and effects.
- Unification and the Hindley–Milner Inference Algorithm
- Let-Polymorphism and the Value Restriction
- Structural Subtyping and the Variance Lattice
- Row Polymorphism for Extensible Records
- Type Classes as Dictionary Passing and the Coherence Problem
- Erasure and Reification of Generic Types
Purity, higher-order abstraction, and recursion schemes.
- Referential Transparency and the Substitution Test
- Call-by-Need Evaluation and In-Place Thunk Update
- Fold as the Universal List Eliminator
- Tail Position, Accumulators, and Continuation-Passing Style
- Fold Fusion and the Elimination of Intermediate Lists
- Catamorphisms and Anamorphisms over Recursive Functors
Dispatch, encapsulation, and linking units.
- Vtable Layout and the Cost of a Virtual Call
- Prototype Chains and Delegation-Based Dispatch
- What a Private Field Actually Hides
- The Fragile Base Class Problem in Compiled Hierarchies
- Inline Caches and Polymorphic Call Sites
- Method Resolution Order in Multiple Inheritance
Actors, CSP, futures, and structured concurrency.
- Mailbox Semantics and Ordering Guarantees in the Actor Model
- Rendezvous and Buffering in CSP-Style Channels
- Futures as Write-Once Cells: Polling, Waking, and Cancellation
- Happens-Before, Data Races, and the Memory Model Contract
- Multiplexing Green Threads onto Kernel Threads
- Structured Concurrency and the Task Scope
Lifetimes, borrow checking, and manual reclamation.
- Stack Frames and the Lifetime of an Automatic Variable
- Move Semantics and the Affine Type Discipline
- malloc, free, and the Conventions That Replace a Type System
- Destructors, Drop Order, and What Unwinding Actually Runs
- Reference Counting and the Cycle It Cannot Break
- Arena Allocation and Ownership by Convention
Macros, reflection, and compile-time evaluation.
- Token Substitution and Tree Substitution in Macro Expansion
- Macro Hygiene and Identifier Capture
- Quasiquotation, Unquotation, and Nesting Depth
- Compile-Time Function Evaluation and Its Limits
- Runtime Reflection: Metadata Layout and Dispatch Cost
- Procedural Macros and the Token Stream Contract
How representative languages execute their semantics.
- Tree-Walking Interpretation and the Cost of Re-Deciding at Every Node
- Stack Bytecode: Fixed Stack Effects and the Dispatch Loop
- Register Bytecode and Windowed Register Allocation in Lua
- Value Representation: Tagged Pointers and NaN Boxing
- Closure Conversion: Flat Closures, Displays, and Boxed Upvalues
- Hidden Classes and Inline Caches in Dynamic Object Models
All Programming Languages articles
- Oct 13, 2026 Token Substitution and Tree Substitution in Macro Expansion Why the C preprocessor rewrites flat token sequences while Lisp macros rewrite parsed forms, and how that choice changes precedence bugs, argument checking, and whether expansion is guaranteed to terminate.
- Oct 11, 2026 Referential Transparency and the Substitution Test What it means for an expression to be replaceable by the value it denotes, which features break that property, and what compilers and proofs gain when it holds.
- Oct 9, 2026 Futures as Write-Once Cells: Polling, Waking, and Cancellation The shared state inside a future, why a poll-based executor needs a waker at all, and how the same cell supports both asynchronous completion and cancellation.
- Oct 5, 2026 Structured Concurrency and the Task Scope Why a spawned task should not outlive its parent, how a scope joins on exit and cancels siblings on failure, and what the nesting rule buys over detached threads.
- Oct 5, 2026 Tail Position, Accumulators, and Continuation-Passing Style Why a call in tail position needs no return frame, how accumulator arguments turn structural recursion into a loop, and what the CPS transformation costs.
- Sep 10, 2026 Algebraic Effects and Effect Rows in the Type System How a computation type records what it may do, how handlers discharge rows, and why effect polymorphism needs its own quantification.
- Aug 22, 2026 Operator Precedence Tables and Why They Are a Design Artifact How precedence is encoded in a grammar, why the table is not arbitrary, and what goes wrong when a new operator is fitted into an existing hierarchy.
- Aug 19, 2026 Bidirectional Type Checking and Where Annotations Flow Why checking a term against a known type is easier than inferring one, how the two judgments hand off to each other, and where the annotation burden returns.
- Aug 15, 2026 Derive Macros and Structural Recursion Over Type Definitions How a derive macro walks a struct or enum field by field to generate implementations, what generic parameters and lifetimes force on the generated code, and why bound inference goes wrong.
- Aug 12, 2026 Catamorphisms and Anamorphisms over Recursive Functors How a recursive datatype becomes the least fixed point of a functor, why its fold is unique, and what an unfold adds that a fold cannot express.
- Aug 6, 2026 Reference Counting and the Cycle It Cannot Break How an atomic count turns ownership into a distributed protocol, why strong counts cannot reclaim a cycle, and what weak references and trial deletion cost to add.
- Aug 4, 2026 Desugaring Boundaries: Where Surface Syntax Ends How a language defines sugar by translation to a core form, why for-loops and async blocks are specified as rewrites, and what the rewrite leaks into error messages.
- Jul 28, 2026 Row Polymorphism for Extensible Records How a row variable records the fields a function does not touch, why lack constraints are needed for extension, and what the algorithm costs.
- Jul 12, 2026 Happens-Before, Data Races, and the Memory Model Contract What a memory model promises about reordering, why a data race is undefined rather than merely surprising, and how release and acquire pairs carry a happens-before edge.
- Jul 12, 2026 Macro Hygiene and Identifier Capture How macro expansion causes identifiers to bind in the wrong scope, how gensyms and syntax objects prevent it, and what hygiene costs in equality checks and in generated names.
- Jul 8, 2026 Growable Stacks and Reduction Budgets in Coroutine Runtimes How a runtime gives each coroutine its own stack segment, why segmented and copied stacks differ, and how a preemption counter bounds the work a coroutine can do.
- Jun 18, 2026 Phase Separation and the Ordering of Compilation Stages Why a macro must be defined before it is used, how phase levels propagate through module dependencies, and what transitive phase shifting costs in compilation work.
- Jun 15, 2026 Mailbox Semantics and Ordering Guarantees in the Actor Model Why an actor mailbox orders messages only per sender pair, what selective receive costs in queue scans, and how an unbounded mailbox becomes the model's characteristic failure.
- Jun 7, 2026 Fold Fusion and the Elimination of Intermediate Lists How the foldr/build rule removes intermediate lists at compile time, what deforestation generalized it to, and why strictness and sharing break the rewrite.
- May 31, 2026 Pattern Matching and the Exhaustiveness Check How a match expression is compiled into a decision tree, why exhaustiveness is decidable for constructors but not for guards, and what an unreachable arm costs.
- May 16, 2026 Evaluation Order, Sequencing Points, and Unspecified Behaviour Why C leaves the order of operand evaluation open, which operators impose sequencing, and how a language that fixes left-to-right evaluation pays for the guarantee.
- May 12, 2026 Hidden Classes and Inline Caches in Dynamic Object Models How a runtime gives dictionary-shaped objects a fixed layout, why each property access site remembers its last hit, and when the cache is invalidated.
- May 12, 2026 Interior Mutability and the Runtime Borrow Flag How a language that checks aliasing at compile time permits mutation through a shared reference, what the runtime flag costs, and how it fails at runtime instead of at compile time.
- Apr 25, 2026 Fold as the Universal List Eliminator Why foldr is the unique homomorphism from lists to any algebra, how the universal property turns programs into equations, and where foldl diverges from it.
- Apr 24, 2026 Tiered Compilation and Deoptimization: Undoing a Speculation How a runtime decides when to compile, what a speculation record contains, and how execution resumes in the interpreter when a guard fails.
- Apr 23, 2026 Runtime Reflection: Metadata Layout and Dispatch Cost What a class descriptor actually contains, why reflective invocation cannot be inlined, and how annotation lookup and dynamic proxies turn a static call into a table walk.
- Apr 23, 2026 What a Private Field Actually Hides How access control is checked, why private members remain reachable through reflection or linking tricks, and why the module rather than the class is the enforceable boundary.
- Apr 14, 2026 Gradual Typing, Higher-Order Casts, and Blame How a boundary between typed and untyped code is enforced by casts, why a higher-order cast must wrap functions, and how blame is assigned when one fails.
- Apr 2, 2026 Rendezvous and Buffering in CSP-Style Channels How an unbuffered channel makes send and receive a single synchronisation event, what a buffer actually buys, and why a blocked channel turns into a deadlock instead of an error.
- Mar 10, 2026 Contextual Keywords and Extending a Grammar in Place How a language adds new syntax without reserving a word, why soft keywords are resolved by the parser rather than the lexer, and what the compatibility technique costs in ambiguity.
- Feb 26, 2026 Quasiquotation, Unquotation, and Nesting Depth How quasiquote builds template structures with holes, why unquote must match the right quasiquote level, and how the level counter decides which parts of a nested template are evaluated.
- Feb 6, 2026 The Dangling Else and How Grammars Resolve Ambiguity Why an if-statement grammar is ambiguous, how shift-reduce parsers settle the conflict by default, and what brace-less and indentation-based designs cost instead.
- Feb 3, 2026 Borrow Checking as a Dataflow Analysis Over Places How a lifetime check becomes a liveness problem on a control-flow graph, why non-lexical lifetimes removed a class of false errors, and where the analysis still gives up.
- Jan 12, 2026 Vtable Layout and the Cost of a Virtual Call How virtual method slots are assigned, why overrides reuse a slot, how multiple inheritance adjusts the this pointer, and what the indirection costs at run time.
- Dec 24, 2025 Safepoints and Stack Maps: Letting a Collector Find Roots Why compiled code must describe its live pointers at specific instruction offsets, how the runtime gets control there, and what polling costs in the hot path.
- Dec 16, 2025 Refinement Types and the SMT Obligations Behind Them How a type is refined with a predicate, why the checker emits verification conditions, and which programs a solver can and cannot decide.
- Dec 8, 2025 Inline Caches and Polymorphic Call Sites How a call site learns the shapes it has seen, what a megamorphic site costs, and why cache invalidation is the hard part of making dynamic dispatch fast.
- Nov 14, 2025 Value Representation: Tagged Pointers and NaN Boxing How a dynamically typed runtime distinguishes integers, heap objects, and doubles inside one machine word, and what each encoding costs in branches, memory, and portability.
- Oct 20, 2025 Procedural Macros and the Token Stream Contract What a procedural macro receives from the compiler, why the interface is a flat token sequence rather than a syntax tree, and what that costs in error reporting and incremental compilation.
- Aug 30, 2025 Destructors, Drop Order, and What Unwinding Actually Runs The order in which destructors run, how exception propagation finds them, and why a destructor that throws or panics changes the shape of the program.
- Aug 25, 2025 Symbol Visibility, Linkage, and the One Definition Rule How exported, hidden, and local symbols differ, why an inline function in a header can violate the one definition rule across shared libraries, and what the linker can detect.
- Jul 30, 2025 Prototype Chains and Delegation-Based Dispatch How property lookup walks a prototype chain, why methods are stored once per prototype instead of once per object, and where the chain design costs lookup time.
- Jul 24, 2025 The Fragile Base Class Problem in Compiled Hierarchies Why adding a virtual function or a data member to a published base class breaks already-compiled clients, which changes are binary compatible, and how interfaces avoid it.
- Jul 12, 2025 Monadic Sequencing and the Encoding of Effects Why an effectful program is a value describing actions, how bind sequences those descriptions, and what the monad laws do and do not guarantee.
- Jun 23, 2025 Declaration Instantiation, Hoisting, and the Temporal Dead Zone How a scope is populated before its body runs, why var and function declarations are visible early while let and const are not, and what the dead zone prevents.
- Jun 7, 2025 Session Types and the Shape of a Channel Protocol How a channel type can encode the order and direction of every message, what duality means for the two ends, and where linear typing stops matching how processes actually behave.
- May 15, 2025 Cooperative Cancellation and the Cancel-Safety Contract Why asynchronous cancellation needs an explicit protocol, what cancel safety means for an operation interrupted at an await point, and where the guarantee is impossible to provide.
- Apr 14, 2025 Let-Polymorphism and the Value Restriction Why generalizing every let binding makes mutable references unsound, how the syntactic value restriction blocks the counterexample, and what relaxed variants admit.
- Apr 3, 2025 Stack Frames and the Lifetime of an Automatic Variable How a function call turns scope into a pointer adjustment, what the frame really holds, and why a local object dies exactly when its block exits.
- Feb 27, 2025 Trait Coherence and Orphan Rules in Open Worlds Why a global instance table needs an ownership restriction, how orphan rules prevent overlapping implementations, and what coherence costs downstream crates.
- Feb 22, 2025 Structural Subtyping and the Variance Lattice Why a record with more fields fits where fewer are expected, why function arguments run the other way, and why a mutable field destroys both.
- Feb 6, 2025 Supervision Trees and the Shape of a Failure Domain How restart strategies bound the blast radius of a failure, what restart intensity actually counts, and why restarting a supervisor can be worse than losing the work it held.
- Jan 28, 2025 Move Semantics and the Affine Type Discipline Why a move is a byte copy plus a compile-time promise, how C++ and Rust enforce that promise differently, and what a moved-from value is still allowed to do.
- Jan 14, 2025 malloc, free, and the Conventions That Replace a Type System What the allocator stores around every block, why the ownership rule must be maintained by hand, and which C idioms encode it well enough to survive review.
- Jan 14, 2025 Module Initialization Order and Cyclic Dependencies How linkers, loaders, and language runtimes order module initialisation, why import cycles produce partially initialised modules, and where the guarantees stop.
- Dec 3, 2024 Software Transactional Memory: Logs, Validation, and Retry How a transaction records its reads and writes in a log, why validation must happen before commit, and what livelock looks like when two long transactions keep colliding.
- Nov 14, 2024 Short-Circuit Evaluation as a Language Guarantee How && and || guarantee operand order, why that guarantee is a control-flow construct rather than an optimisation, and what nullable and optional chaining borrow from it.
- Nov 8, 2024 Exception Unwinding: Table-Driven Cleanup and the Cost of Try How a raise becomes a search through per-function tables, why some runtimes walk the stack twice, and what the zero-cost claim about exceptions really means.
- Oct 24, 2024 Recursion Schemes: Catamorphisms, Anamorphisms, and Hylomorphisms The zoo of structured recursion operators, what each adds over the plain fold, and how the composition of a fold with an unfold collapses into a single pass.
- Sep 12, 2024 Multiplexing Green Threads onto Kernel Threads How an M:N scheduler maps lightweight tasks onto a fixed pool of OS threads, what work stealing does to locality, and where a blocking call forces the scheduler to compensate.
- Aug 15, 2024 Unification and the Hindley–Milner Inference Algorithm How ML-family languages recover types without annotations: unification variables, the occurs check, and the level discipline that keeps generalization cheap.
- Jun 8, 2024 Unsafe Abstraction Boundaries and What Soundness Actually Costs The contract an unsafe block transfers from compiler to programmer, the invariants a safe wrapper must maintain, and how those invariants fail in practice.
- Jun 5, 2024 Multi-Stage Programming and Cross-Stage Persistence How staged languages type the distinction between code and its generation, what run and splice mean at each level, and why a value captured at one stage must be embeddable in the next.
- May 23, 2024 Expansion Depth Limits and Token Opacity Why a recursive pattern-matching macro consumes one level of expansion depth per element it processes, how the recursion limit is raised, and why a captured fragment cannot be re-matched by a later pattern.
- May 15, 2024 Expression-Oriented Syntax and the Value of a Block What changes when every construct produces a value, how a block’s trailing expression becomes its result, and why the statement form survives in languages that removed it.
- Mar 31, 2024 Type Classes as Dictionary Passing and the Coherence Problem How ad-hoc polymorphism compiles to a record of functions, why instance resolution must be deterministic, and where orphan instances break the guarantee.
- Jan 27, 2024 Stack Bytecode: Fixed Stack Effects and the Dispatch Loop How a stack machine encodes operands implicitly in the stack pointer, why verifiers care about static stack depth, and what the dispatch loop costs per instruction.
- Jan 17, 2024 Lenses and Traversals as Composable Immutable Accessors How the van Laarhoven encoding represents a lens as a function over functors, why the laws are not enforced, and what composition costs at run time.
- Jan 10, 2024 Method Resolution Order in Multiple Inheritance How C3 linearisation produces a consistent method order from a class graph, why depth-first search fails on diamonds, and what the monotonicity property forbids.
- Oct 13, 2023 Applicative and Generative Functors in Modular Type Checking Why two applications of the same functor may or may not produce compatible abstract types, how path-based strengthening decides it, and what sealing hides.
- Jun 22, 2023 Compile-Time Function Evaluation and Its Limits How a compiler runs ordinary functions during translation, why the interpreter inside the compiler must refuse some operations, and where the boundary between constant folding and program execution falls.
- Jun 19, 2023 How Escape Analysis Removes a Heap Allocation How a compiler proves that an allocation cannot be observed outside its function, and what it must give up when object identity or a stored pointer blocks the proof.
- Jun 6, 2023 Call-by-Need Evaluation and In-Place Thunk Update How a lazy argument becomes a shared thunk, why forcing it overwrites the thunk with its value, and where the resulting retention of unevaluated expressions costs memory.
- Mar 5, 2023 Arena Allocation and Ownership by Convention Replacing per-object ownership with region ownership: the bump-pointer fast path, the constraints it imposes on destructors, and where the pattern appears in real allocators.
- Feb 26, 2023 Tree-Walking Interpretation and the Cost of Re-Deciding at Every Node Why an interpreter that evaluates syntax nodes spends most of its time on type dispatch and environment lookup, and which of those costs a bytecode compiler removes.
- Jan 30, 2023 Register Bytecode and Windowed Register Allocation in Lua How a register-based VM names operands inside a per-call window, why that cuts instruction count, and what the compiler must compute to keep the window small.
- Jul 9, 2022 Automatic Semicolon Insertion and Restricted Productions How JavaScript decides where statements end without semicolons, why the rule lives in the parser rather than the lexer, and which line breaks silently change meaning.
- Jul 4, 2022 Closure Conversion: Flat Closures, Displays, and Boxed Upvalues How a nested function that references an outer variable becomes a heap object with a specific layout, and what each representation of the captured environment costs per call.
- Jan 6, 2022 Erasure and Reification of Generic Types Why Java cannot ask whether a list holds strings, how erasure turns generics into casts, and what monomorphization and reification cost instead.
- Dec 12, 2021 Free Monads and Defunctionalized Interpreters How a free monad turns a program into a syntax tree of requests, why the interpreter is a fold, and where the left-nested bind makes that tree quadratic.