B
Ken Thompson's typeless systems language for the PDP-7, squeezed from BCPL to fit 8K bytes of memory, and the direct ancestor of C.
Created by Ken Thompson (Bell Labs), with early contributions from Dennis Ritchie
B was a small, typeless programming language that Ken Thompson created at Bell Labs around 1969-1970 to give the fledgling Unix project on the DEC PDP-7 a system-implementation language better than raw assembler. Dennis Ritchie, who worked alongside Thompson and later built C directly out of B, described it succinctly: B was “BCPL squeezed into 8K bytes of memory and filtered through Thompson’s brain.” It is not a language many people write today, but it is one of the most consequential languages in computing history, because extending it with a type system produced C.
History and Origins
From an abandoned Fortran to B
By 1969, Bell Labs had pulled out of the Multics project, and Ken Thompson, Dennis Ritchie, and a small group of colleagues were building their own operating system on a spare DEC PDP-7 — a machine with only 8K 18-bit words of memory and no useful software of its own. The group wanted a higher-level implementation language rather than assembler, and had experience with BCPL (Basic Combined Programming Language) from the Multics years. According to Ritchie’s own history of C, Thompson first made “a rapidly scuttled attempt at Fortran” for the PDP-7, then abandoned it and wrote a language of his own instead, which he called B.
The name’s origin is not fully settled. Ritchie wrote that it “most probably represents a contraction of BCPL,” though he also noted an alternate theory that it derived from Bon, an earlier, unrelated language Thompson had designed during the Multics era (reportedly named after his wife Bonnie, or after a Tibetan religious tradition mentioned in an encyclopedia entry Thompson quoted in Bon’s manual). Both explanations trace to Thompson and Ritchie themselves, and neither has been definitively confirmed over the other.
Squeezed to fit the machine
B kept BCPL’s underlying semantics almost intact while reworking its syntax to fit a far smaller compiler. Both languages are effectively typeless: the only data type is the machine “word” or “cell,” and operators like + simply perform the hardware’s integer arithmetic regardless of what the operand is meant to represent. Because memory is a flat array of these cells, a cell can double as a pointer, and B used a unary * for indirection (BCPL had used rv, later !). Pointer arithmetic on arrays followed directly from this model: V[i] was defined in terms of *(V+i).
Storage constraints, not just taste, drove several changes from BCPL. BCPL’s compiler analyzed an entire parsed program held in memory before generating output; B’s compiler, cramped for space, had to generate output in a single pass as soon as possible, and this restructuring of the grammar carried forward into C. B also dropped BCPL’s “global vector” linkage scheme (where programmers manually assigned numeric offsets for external symbols) in favor of requiring, in its earliest form, that an entire program be presented to the compiler at once; a conventional linker came later. Other differences were closer to stylistic choices: B used = for assignment instead of BCPL’s :=, and /* */ for comments instead of BCPL’s end-of-line // — a PL/I-flavored choice that C++ would later reverse.
Thompson’s B compiler on the PDP-7 did not generate native machine instructions. Instead it produced “threaded code,” an interpreted scheme where the compiler emits a sequence of addresses of prewritten code fragments executed against a simple stack machine. This kept the compiler itself small enough to survive in 8K bytes, but it also meant B programs ran far slower than hand-written assembly — a limitation that eventually helped motivate the move to a compiled, typed successor.
Among B’s original contributions, independent of BCPL, were generalized assignment operators such as x =+ y (meaning “add y to x,” borrowed via Doug McIlroy’s TMG implementation from an Algol 68 idea, and later corrected to today’s += form in 1976) and the ++ and -- increment/decrement operators. Ritchie was explicit that these were not inspired by the PDP-11’s auto-increment addressing modes, since “there was no PDP-11 when B was developed” — the PDP-7 already had a handful of auto-increment memory cells that may have suggested the idea, but the stronger motivation was simply that ++x produced smaller compiled code than x=x+1.
Bootstrapping and early use
Thompson bootstrapped B by rewriting its own compiler in B, and went further by writing what Ritchie called “a small tour de force”: a genuine cross-compiler, written in B, that translated B source into native instructions for a 36-bit GE-635 mainframe — running on an 18-bit PDP-7 with only 4K words of user address space. On the PDP-7 itself, few programs beyond the B compiler were written in the language, since the machine was judged too small and slow for more; a notable exception was an early version of the dc desk calculator utility.
When Bell Labs acquired one of the first-shipped DEC PDP-11 systems in 1970, B moved with the project. Because the PDP-11’s disk took months to arrive, Ritchie wrote the threaded-code fragments and a small assembler (itself coded in B) needed to run B programs on the new machine before there was any operating system for it at all; dc became the first interesting program tested on the bare PDP-11. By 1971, with a small but growing community of Unix users at Bell Labs, B — despite its performance problems — had picked up a library of service routines and was in active use for new software; Stephen C. Johnson wrote the first version of the yacc parser generator in B during this period.
Design Philosophy
B’s guiding idea was economy under extreme constraint. Every language feature had to justify the memory it cost the compiler, and Thompson repeatedly rewrote the compiler as it grew to reclaim space traded away by new features. The result deliberately abandoned type safety and static checking in favor of a model where the programmer, not the compiler, was responsible for knowing what a given “word” represented at any moment — a philosophy well suited to a small team writing an operating system for a machine with almost no memory to spare, but one that would not scale gracefully once B moved to byte-addressed hardware.
Why B Stopped Being Enough
The PDP-11 exposed B’s typeless model as a liability rather than an economy. Ritchie identified three specific problems in his own account of C’s development: B’s BCPL-derived string handling, based on packing and unpacking characters into word-sized cells, felt “clumsy… even silly” on a byte-oriented machine; the PDP-11’s promised (though not yet delivered) floating-point hardware needed a data representation that did not fit in a single machine word the way it had on B’s word-addressed predecessors; and treating every pointer as a word index, rather than a byte address, forced a runtime scaling conversion on every pointer dereference.
In 1971, Ritchie began addressing these problems by adding a character type to B and rewriting the compiler to emit native PDP-11 instructions instead of threaded code — a language he called “New B,” or NB. NB existed only briefly and was never fully documented on its own; it supported int and char, arrays of them, and pointers to them, but nothing more. Extending that type system further, especially to support structures, forced the key semantic break with BCPL and B: rather than storing a materialized pointer for an array name, the compiler would create that pointer on the fly whenever the array name appeared in an expression — the rule, Ritchie noted, that survives in C today. This solved problems that had no clean answer in B’s flat, typeless memory model, particularly for structures containing arrays. NB’s evolution into a fuller type system through the early 1970s produced C, and by around 1973 B itself had been retired at Bell Labs as Unix development moved to the new, compiled, typed language.
Legacy
B is remembered less for its own use than for what it led directly to. Nearly every syntactic idiom recognizable in C — semicolon-terminated statements, auto/static style declarations, the =+-turned-+= compound assignment operators, ++/--, and the *p and p[i] treatment of pointers and arrays — was already present in B, carried over from Thompson’s compression of BCPL. Brian Kernighan’s 1972 Bell Labs memo “A Tutorial Introduction to the Language B” is widely credited with the first appearance of a “hello, world” program in programming literature (split awkwardly across several external variables, since a B character constant held only four ASCII characters at a time) — a tradition that outlived the language itself by decades. B is not maintained or used for new development today; its significance is historical, as the missing link between BCPL’s typeless simplicity and the typed systems-programming model that C, and nearly everything built on top of it, still uses.
Timeline
Notable Uses & Legacy
Early Unix utilities on the PDP-7
B was used for a handful of early Unix programs on the memory-starved PDP-7, most notably an early version of the dc arbitrary-precision desk calculator, since the machine was considered too small and slow to rewrite the whole operating system in it
First PDP-11 Unix bring-up
Before PDP-11 Unix had its own compiled kernel or a working disk, B programs compiled to threaded code (including dc) were the first software tested on the new machine, using code fragments and an assembler that Dennis Ritchie wrote in B
First version of yacc
Stephen C. Johnson wrote the original version of the yacc parser generator, later a cornerstone of Unix compiler construction, in B during 1971