Skip to content
ALB Wiki

SNOBOL and Icon

SNOBOL (StriNg Oriented symBOlic Language) is a family of programming languages built at Bell Telephone Laboratories between 1962 and 1967 by David Farber, Ralph Griswold, and Ivan Polonsky — and Icon is its direct descendant, designed by Griswold at the University of Arizona in 1977–78. Between them they introduced two of the most quietly consequential ideas in the history of programming: the pattern as a first-class data type, and goal-directed execution driven by generators. Every programmer who has ever written a regular expression, or called a Python yield, is standing downstream of these two languages.

SNOBOL4, the mature form, was the most powerful text-processing language of its era — arguably of any era. It treated patterns not as strings of cryptic notation but as structured data that could be built, stored, passed to functions, and even modified while a match was in progress. Its matcher could express full Backus–Naur form grammars — a class of problem provably beyond ordinary regular expressions, which would not acquire comparable power for forty years. Icon took the same engine — success, failure, and backtracking — and wrapped it in the ALGOL-style syntax the industry had learned to expect, adding the generator, a construct so natural that Python's designers cited Icon by name when they adopted it in 2001.[1]

This article tells the whole story: the language itself, its history and lifetime, and the concepts it gave the world — pattern matching, goal-directed programming, generators, and the entire tradition of string-processing languages that followed.

The world before strings

To understand what SNOBOL did, you have to remember what programming looked like when it arrived. The languages of the 1950s were built for numbers. FORTRAN (1957) processed arrays of floating-point values; its string handling was, charitably, an afterthought — text lived in fixed-length fields manipulated through format statements. COBOL (1959) thought in records: fixed-layout rows of data for payroll and inventory. ALGOL (1958, 1960) gave the world block structure and recursion — and essentially no strings at all.

But computers were already drowning in text: programs themselves, data records, natural language. The first people to notice were the linguists. At MIT in 1957, Victor Yngve's group built COMIT, the first language designed specifically to manipulate strings — motivated by the dream of Machine translation, which in those optimistic years seemed a few years from solved. COMIT treated text as something to be rewritten by rules: match a fragment of the input against a pattern, replace it with something else, and repeat. That single idea — find this, replace it with that — is the seed of everything in this article.

COMIT was brilliant and awkward in roughly equal measure. Its notation was dense, its execution slow, and its portability nonexistent. A second early language, TRAC (1964), pursued macros and text generation. The stage was set for someone to do string processing properly — and the people who did were not linguists at all, but researchers at the most fertile laboratory in the history of computing.

Bell Telephone Laboratories in the 1960s was a place where a researcher could be handed a problem, a mainframe, and effectively no supervision. The Programming Research Studies department at the Holmdel, New Jersey site — six people — sat inside an institution that in a single decade produced the transistor's successors, Unix, C, information theory's mature form, and half the theoretical foundation of the digital century. Computing there meant Punched cards, batch queues, an IBM 7090 shared by a buildingful of researchers, and turnaround measured in the time it took to walk a card deck to the machine room and find your printout in a bin. Interactive terminals were a rumor. You got a few shots a day; each one had to count, which is precisely the environment in which dense, expressive notation thrives.

Bell Labs and the birth of SNOBOL

Bell Labs, Holmdel, New Jersey — the Eero Saarinen "biggest mirror ever" where SNOBOL was born (photo: Wikimedia Commons, CC BY-SA)
Bell Labs, Holmdel, New Jersey — the Eero Saarinen "biggest mirror ever" where SNOBOL was born (photo: Wikimedia Commons, CC BY-SA)

In the fall of 1962, three members of the six-person Programming Research Studies department at Bell Labs in Holmdel, New Jersey — David Farber, Ralph Griswold, and Ivan Polonsky — were frustrated. Their actual work involved the symbolic manipulation of polynomials, symbolic integration, and the study of Markov chains. Their tool was SCL, a language written by department head Chester Lee — slow, low-level, and producing "volumes of code for even simple projects." They considered adopting COMIT, found it wanting, and did what Bell Labs people did in that golden age: they wrote their own language.[2]

The first versions ran on the lab's IBM 7090 mainframe in early 1963, and by summer the language was in use across Bell. It had one data type — the string — no functions, no declarations, almost no error control, and a syntax of beautiful simplicity: every statement was a pattern match with an optional replacement and an optional branch. Its authors called it a personal tool. Tools that good never stay personal.

SEXI, or how SNOBOL got its name

The naming story is one of computing's great anecdotes, told by Farber himself. The team first settled on SEXI — "Symbolic EXpression Interpreter." All went well until the day Farber submitted a batch job; on the JOB card, in standard Bell Labs style, he punched the program name and his own: SEXI Farber.

"One of the Comp Center girls looked at it and said, 'That's what you think.'"

A new name was required. The team sat, talked, drank coffee, shot rubber bands. After far too long someone — most likely Ralph — said they didn't have "a snowball's chance in hell" of finding a name. The room yelled at once: SNOBOL — in the spirit of the era's "-BOL" languages. The expansion came after: StriNg Oriented symBOlic Language, a backronym stretched as far as it would go.[3]

The three authors

David J. Farber in 2008 — co-creator of SNOBOL, later "the grandfather of the Internet" for his work on early distributed systems (photo: Wikimedia Commons, CC)
David J. Farber in 2008 — co-creator of SNOBOL, later "the grandfather of the Internet" for his work on early distributed systems (photo: Wikimedia Commons, CC)

The trio behind SNOBOL each went on to notable careers. David J. Farber left Bell Labs for a long academic career — at UC Irvine, the University of Delaware, Carnegie Mellon, and finally the University of Pennsylvania, where he became one of the elders of computer networking. His students built early pieces of the Internet's infrastructure; the community nicknamed him, with affection, a grandfather of the Internet, and his Interesting People mailing list ran for decades as the industry's back channel. Ivan P. Polonsky continued at Bell Labs in language research; and Ralph E. Griswold — the member of the trio for whom string languages became a life's work — carried SNOBOL to the University of Arizona in 1971 and spent the next three decades extending the family through SL5, Icon, and Unicon. He died in 2006, having out-published, out-implemented, and out-taught nearly everyone in his niche. The SNOBOL lineage is unusual in language history for having a single continuous steward: nearly every idea in this article passed through one man's mind, twice, twenty years apart.

The versions: SNOBOL 1 through 4

SNOBOL evolved quickly — and its early history is a lesson in how languages actually grow.

SNOBOL1 (1962–63) was the personal tool: string processing with pattern matching and replacement, one datatype, minimal syntax, written in IBM 7090 assembly.

SNOBOL2 (April 1964) added built-in functions and the ability to link in external assembly code. It was used mostly inside Bell, though it reached as far as MIT's Project MAC. Built-in functions, once present, immediately taught users to want user-defined ones.

SNOBOL3 (July 1964) supplied exactly that — programmer-defined functions — and became genuinely popular. Other sites reimplemented it for other machines, and incompatible dialects bloomed. Success had created the classic problem: the authors were being bug-reported against versions they never wrote.

SNOBOL4 (1967) was the answer and the masterpiece. The team decided to define the language once, completely, and make it run everywhere — an extraordinary decision for 1967. The interpreter was written in assembly, but through assembler macros it targeted an abstract machine: the SNOBOL Implementation Language, or SIL, a generalization of string-manipulation macros by Douglas McIlroy — the same McIlroy who was then inventing pipes down the hall. To port SNOBOL4, you reimplemented the SIL macros on your machine; the whole language came along for free. SNOBOL4 was running on the IBM 360 in 1967 and was rapidly ported essentially everywhere. It is one of the earliest serious virtual-machine implementations in computing history — the JVM's ancestor, by two decades.[4]

It is worth pausing on what else existed in 1967, because SNOBOL4's ambition only registers against the backdrop. FORTRAN IV was five years old. BASIC was three. PL/I was new. ALGOL 60 had given the world recursion and blocks but no strings to speak of. LISP had symbolic computation and its own exotic syntax; Prolog was still five years in the future, unbuilt. Into that world landed a language with garbage collection, a portable virtual machine, programmer-defined datatypes, associative arrays, runtime code generation, and a pattern facility equivalent to context-free grammars — a feature list that reads like a 1990s scripting language's sales pitch, shipped when the moon landing was still two years away.

McIlroy struck twice. In 1969 he insisted SNOBOL4 add an associative-array type — the table — decades before "hash map" or "dictionary" became every language's standard feature. It arrived and stayed.

Under the hood: what SNOBOL4 could do

Behind the five-part statement sat an unusually modern machine. SNOBOL4 supported integers, limited-precision reals, strings, patterns, arrays, tables, and programmer-defined datatypes — the DATA function let a user declare record types with named fields, a facility comparable to COBOL's records and ahead of Pascal's. Everything lived in a single garbage-collected heap — automatic memory management on a 1967 mainframe, when most languages still treated memory as the programmer's problem.[5]

Most startling of all, SNOBOL4 strings could be turned into programs at runtime. EVAL evaluated a string as an expression, and the CODE function took a string of SNOBOL source, compiled it inside the running program, and returned it as a callable value — eval-style metaprogramming, or JIT-compilation from the user's seat, on a machine that cost millions and shared an hour among dozens of users. A program could write a program. This produced the celebrated SNOBOL foot joke: a program that reads its own source, strips every line containing the letter e, runs the result — and amputates itself, because a source file with every e removed is a foot short. Dr. Dobb's commemorated the genre as "Programs That Transform Their Own Source Code"; SNOBOL4 made such self-modification routine enough to joke about.EVAL/CODE self-modification tradition.">[6]

The SPITBOL extensions, later absorbed into every modern implementation, pushed further still: nested conditional expressions, immediate assignment during matching, and the ability for a function called mid-pattern to alter the pattern being matched. A SNOBOL4 pattern was less a query than a live computation with side effects — the pattern could think about itself while it ran.

What a SNOBOL program looks like

SNOBOL is column-oriented — a punched-card-era language — and every statement has the same five parts, all optional:

Anatomy of a SNOBOL statement: label, subject, pattern, = object, :goto transfer — every part optional
Anatomy of a SNOBOL statement: label, subject, pattern, = object, :goto transfer — every part optional

A label marks a jump target. The subject is the string under examination; the pattern is what to match against it; = object replaces whatever matched; and the : transfer sends control to a label on success :S(...), on failure :F(...), or unconditionally. That is the entire language's control flow: there is no if, no while, no for — only match, and branch on the outcome.

        OUTPUT = "Hello, World!"
END

Hello World is one assignment to the pseudo-variable OUTPUT, which prints whatever is assigned to it. Something with a little motion — greet the user differently by initial:

        OUTPUT = "What is your name?"
        Username = INPUT
        Username "J"                                        :S(LOVE)
        Username "K"                                        :S(HATE)
MEH     OUTPUT = "Hi, " Username                            :(END)
LOVE    OUTPUT = "How nice to meet you, " Username          :(END)
HATE    OUTPUT = "Oh. It's you, " Username
END

Line three matches Username against the pattern "J" — implicitly anchored, so it matches only if the name begins with J. On success it jumps to LOVE; otherwise it falls through to the next line. The :(END) is an unconditional transfer. A program that keeps reading until the input runs out shows the idiom at full strength — LEN(1) is a pattern that succeeds only if at least one character remains:

        OUTPUT = "Press return alone to finish"
        NameCount = 0                                        :(GETINPUT)
AGAIN   NameCount = NameCount + 1
        OUTPUT = "Name " NameCount ": " PersonalName
GETINPUT OUTPUT = "Name please: "
        PersonalName = INPUT
        PersonalName LEN(1)                                 :S(AGAIN)
        OUTPUT = "Finished. " NameCount " names requested."
END
A punched card — SNOBOL's native habitat. Labels and the : transfer column are a card-format language's grammar
A punched card — SNOBOL's native habitat. Labels and the : transfer column are a card-format language's grammar

It looks alien because it is alien — this is programming as a sequence of rewrite rules, closer in spirit to COMIT and to Prolog's clause logic than to anything ALGOL-shaped. The same five-part line handles pattern matching, substitution, I/O, and every conditional and loop the program will ever need.

Pattern matching

Pattern matching is SNOBOL's reason to exist, and the reason it still matters. The idea generalizes what a regular expression does — find structure in text — and lifts it into the language itself.

A SNOBOL pattern is a first-class data type: a value like a string or a number, stored in variables, passed to functions, returned from functions, concatenated into larger patterns, and built at runtime. Two operators construct them: concatenation (adjacency — A B matches A then B) and alternation (the | operator — A | B matches A or B). Patterns nest freely. This looks ordinary now because JavaScript regex literals and parser combinator libraries made it ordinary. In 1967 it was a decade ahead of everyone.

The matcher itself is a backtracking engine — the same algorithmic family as Prolog's resolution, developed in the same years. Try an alternative; if the match later fails, back up and try the next. SNOBOL4 patterns can capture substrings during the match (pattern . variable binds the matched text), invoke user functions mid-match that can steer or even rewrite the pattern while it runs, and express recursive structures: a pattern can contain a reference to itself. That last property is the crucial one — it lets a SNOBOL pattern describe a full context-free grammar, the same class as Backus–Naur form. A SNOBOL program could implement a language interpreter almost directly from its published BNF; a macro assembler for a theoretical machine was reportedly a few hundred lines, with each new instruction costing one line.[7]

Regular expressions, by contrast, are regular — the name is a theorem, not a description. They cannot match balanced parentheses, cannot parse a grammar, cannot recurse. They were good enough for "find text like this" and so they won the popular market; AWK and later Perl carried them to ubiquity in the 1980s and 90s while SNOBOL's richer model faded from teaching. Only in December 2007, with recursive patterns in Perl 5.10, did the mainstream finally acquire what SNOBOL4 had shipped in 1967 — a forty-year gap in which the less capable tool was simply the fashionable one.(?R) recursion (December 2007); Gimpel 1973 supplies the theory.">[8]

* a SNOBOL4 pattern for "word word" — a doubled word
* built as data, matched as structure
        TWO  =  BREAK(" ") . FIRST  " "  *FIRST
        LINE  "the the end"  TWO                              :S(DOUBLE)
        OUTPUT = "no doubled word"                            :(END)
DOUBLE  OUTPUT = "doubled: " FIRST
END

Here BREAK(" ") . FIRST matches up to a space and captures it into FIRST, " " matches the space literally, and *FIRST matches the captured text again — the pattern reads like the sentence it describes. A practical parser for "a complete name and international postal mailing address" — the example the literature liked to give — is expressible the same way, and was.

The primitive vocabulary

Real patterns are assembled from a small vocabulary of built-in matchers, each one a generator of possible spans:

PrimitiveMatches
LEN(n)any n characters
SPAN("0123456789")a run of digits — longest possible
BREAK(" .")everything up to a space or period
ANY("aeiou")exactly one vowel
NOTANY("012")one character that is not a digit
ARBanything — the reluctant wildcard
REMthe remainder of the string
POS(0), RPOS(0)anchored: start / end of subject
BAL("()")a balanced-parentheses expression — the showcase recursive primitive
FAIL, SUCCEED, ABORTcontrol the match engine itself

BAL deserves the spotlight it always gets: matching balanced delimiters is the canonical problem that breaks regular expressions, and SNOBOL4 shipped it as a builtin. Combined with conditional captures — pattern . variable binds text on success, pattern $ variable binds cursor position — and the alternation/concatenation operators, the vocabulary scales from tokenizing a line to parsing a language. Patterns being data, a program could store a library of grammar fragments in a table and compose full parsers at runtime:

        DIGIT   =  ANY("0123456789")
        INT     =  POS(0) SPAN("0123456789") RPOS(0)
        INPUT   "4096"  INT                                :S(ISINT)
        OUTPUT  = "not an integer"                         :(END)
ISINT   OUTPUT  = "integer!"
END

Scale that same technique to a real grammar and the machinery shows its muscle. A date parser — "25 December 1745" — is a handful of pattern definitions, each readable as what it describes:

        DIGITS  =  "0123456789"
        DAY     =  POS(0) SPAN(DIGITS) . N  " "
        MONTHS  =  "January" | "February" | "March" | "April"
+               |  "May" | "June" | "July" | "August"
+               |  "September" | "October" | "November" | "December"
        DATE    =  DAY  MONTHS . M  " "  SPAN(DIGITS) . Y  RPOS(0)

        INPUT   DATE                                       :S(OK)
        OUTPUT  = "not a date"                             :(END)
OK      OUTPUT  = N " of " M ", " Y
END

+ continues a definition on the next line. The whole thing — grammar definition, match, capture, and formatted output — fits in a dozen lines, and the pattern DATE is itself a value that could be stored, combined, or passed elsewhere. This is the difference a first-class pattern type makes: a regex solution embeds the same logic as one unreadable string; the SNOBOL version is a grammar, composed like a grammar, debugged like data.

Text processing languages

SNOBOL4 became the canonical text-processing language — the tool for the jobs the numeric languages couldn't see. The pattern fit a niche that was exploding in the 1970s: the Digital humanities, before the field had that name. Humanists needed to index, collate, translate, and transform text at scale — concordances, stylistic analysis, machine-translation experiments, catalogues — and SNOBOL4 was essentially the only serious instrument. It was taught widely at American universities in the late 1960s and early 1970s, and used through the 1970s and 80s; Susan Hockey's SNOBOL Programming for the Humanities (Clarendon Press, 1985) is the period's standard textbook.[9]

Its second home was language research itself: compilers, formal grammars, and early artificial intelligence — especially machine translation and natural-language comprehension, whose research community ran on the PDP-10 machines where SNOBOL4 lived comfortably. The file editor of the Michigan Terminal System adopted SNOBOL4 patterns as its search language — an editor whose regex equivalent was a full grammar engine.

The teaching footprint mattered as much as the research one. A generation of students met serious string handling through SNOBOL4 in the late 1960s and early 70s — the same years their engineering classmates were meeting FORTRAN. Three books did the carrying: the "green book" itself (Griswold, Poage & Polonsky's The SNOBOL4 Programming Language, 1968, with its famously rigorous-but-readable exposition), Griswold's own Macro Implementation (1972) for the internals-curious, and Gimpel's Algorithms in SNOBOL4 (1976), a genuine algorithms text that happened to be written in a pattern language. Emmer's SNOBOL4+ (1985) carried the language onto personal computers, and Hockey's humanities text into seminar rooms where the machine had previously been a punch-card curiosity. For a niche language, SNOBOL4 was unusually well-documented — one reason it still reads well today.

The genre SNOBOL4 defined has a recognizable genealogy afterward: AWK (1977, also from Bell Labs) streamlined the match-and-act model for line-at-a-time files; Perl (1987) fused it with regex and shell convenience into the web-era glue language; and every modern "text manipulation" facility — sed, grep, Python's re, JavaScript's regexes, jq — lives somewhere on the spectrum SNOBOL4 staked out.

Why the better tool lost

It is worth asking plainly why SNOBOL4 faded while objectively weaker tools prospered, because the answer is a standing lesson in language history:

  • Syntax carried the era's fingerprints. Column layout and label-branch flow belonged to punched cards; once if/then/while became the industry's muscle memory, SNOBOL's transfer column read like assembly.
  • Regular expressions were smaller. For 90% of real work — find this string, split this line — a compact notation that fit inside an editor beat a grammar engine. The market for "a complete name and international postal mailing address" was real but narrow.
  • AWK and Perl were free and on the machine you already had. Unix made them ambient; SNOBOL4 remained a language you installed deliberately.
  • No champion survived. When Griswold's group moved on to Icon, SNOBOL lost its research engine. Perl had Larry Wall writing annual State of the Onion addresses; SNOBOL had a library of excellent books and no marketing department.

The pattern recurs throughout this encyclopedia: technical superiority loses to distribution, convention, and luck — which is exactly why preserving the knowledge matters. The better tool didn't disappear; it just stopped being looked at.

An IBM 7090 — the machine SNOBOL1 ran on at Bell Labs in 1962–63 (NASA photo)
An IBM 7090 — the machine SNOBOL1 ran on at Bell Labs in 1962–63 (NASA photo)

Implementations and dialects

The classic SNOBOL4 ran on the PDP-10 — slowly, because a portable interpreter pays in cycles. James Gimpel fixed that twice. In 1972, at Bell Labs Holmdel, he designed SITBOL, a native PDP-10 implementation, and used it as the semester project for a string-processing course at Stevens Institute of Technology (the "ST" in the name): students each implemented a slice in PDP-10 assembler, and the finished interpreter was a full-featured, high-performance SNOBOL4. Gimpel's greater work was SPITBOL — the compiled implementation that gave SNOBOL4 near-native speed and became the reference implementation for decades; after years as a commercial Catspaw product, SPITBOL was released as free software under the GNU GPL in April 2009.[10]

The ecosystem produced its own odd children. Snostorm (1970s, Fred Swartz, University of Michigan) was a preprocessor adding structured-programming constructs to SNOBOL for MTS sites. Snocone (Andrew Koenig, 1985) went further — a self-contained block-structured language on SNOBOL semantics. Minnesota SNOBOL4 by Viktors Berstis reproduced the IBM mainframe original most faithfully on PCs, down to Fortran-style FORMAT support. Catspaw, Inc. sold commercial ports for DOS, Macintosh, Sun and RS/6000 — all now free. GNU's Ada compiler carries GNAT.Spitbol, the SPITBOL string semantics callable from Ada. And the language runs today: Macro SNOBOL4 by Phil Budne and the BSD-licensed CSNOBOL4 port keep the original Bell Labs implementation compiling wherever C exists.

A DEC PDP-10 — the classic SNOBOL4 machine, and the platform of the AI and language research community (photo: Wikimedia Commons, CC BY-SA)
A DEC PDP-10 — the classic SNOBOL4 machine, and the platform of the AI and language research community (photo: Wikimedia Commons, CC BY-SA)

Griswold goes west: SL5

In August 1971, Ralph Griswold left Bell Labs for a professorship at the University of Arizona, bringing SNOBOL4 with him — and National Science Foundation support to keep evolving it. By then the language's design debts were obvious. Its column format and label-driven branching belonged to the punched-card age; structured programming — if/then, while, blocks — had become table stakes since ALGOL 60. SNOBOL4's semantics were brilliant and its syntax was dead.

Griswold's first attempt at a successor, SL5 ("SNOBOL Language 5," 1977), tried to graft the success/failure machinery onto conventional control structures. He judged the result a failure — the mechanisms fought each other. In 1977 he went back to first principles and set the constraints for the real successor: keep SNOBOL4's philosophical and semantic basis; take SL5's syntax and its features; drop the over-general procedure mechanism.[11]

The new language was SNOBOL5 for a while, but it had drifted too far from the name. They considered s — an homage to c, a sibling tribute to C — and abandoned it as untypesettable. Irving and bard were proposed and dropped; "TL" — "The Language" — was too coy. Then Xerox PARC's graphical-interface work put the word icon into the computer lexicon, and the name was chosen — a decision Griswold later regretted, since "icon" had no graphical features whatever and the name confused everyone it attracted.[12]

Icon

Icon (1978) is the idea of SNOBOL rebuilt for the structured-programming era: Pascal-flavored syntax (:=, procedure, end) with C's braces and a main procedure, dynamically typed, no declarations, automatic conversion between numbers and strings. On the surface it looks like a pleasant scripting language of its decade. Underneath it runs the strangest and most elegant control model any mainstream-adjacent language has ever shipped.

Goal-directed programming

In conventional languages a lookup that finds nothing returns a sentinel — -1, null, EOF — and the programmer writes tests everywhere: if (pos == -1), while ((c = read()) != EOF). In SNOBOL, an operation that couldn't produce a result failed, and the :S(...)/:F(...) transfers steered execution by it. Icon keeps the semantic — an expression succeeds with a value, or fails — and wires it into ordinary structured syntax. if, while, every, and friends are all driven by success and failure rather than by Boolean tests.

The payoff is concrete. File-copying in Java requires the EOF sentinel and an explicit comparison; in Icon it is:

while write(read())

read() produces a line, or fails at end of file; failure propagates through write into while, which stops — correctly, silently, by design. Comparisons work the same way: a < b is an operator that succeeds and returns b, or fails — so a < b < c does exactly what it looks like, since the first comparison hands its second operand to the second. And failure is not an exception: reaching end of file is an expected outcome, not a thrown emergency. Icon simply declined the sentinel-and-test industry that occupied every other language of its generation.[13]

Backtracking completes the picture: when a branch fails, Icon can rewind to an earlier point and try another alternative — and reversible assignment (<-, <->) exists so that variables changed inside a failed computation restore themselves, a built-in atomicity that string scanning relies on constantly:

{
  i <- 10 &
  j <- find(pattern, inString)
}

If find fails, the block fails — and i <- 10 rolls itself back, leaving no phantom assignment behind. In a language without reversibility, a failed parse attempt leaves the cursor wherever the attempt abandoned it, and the next attempt starts from a corrupt state. Icon's scan either commits its cursor movement or undoes it, which is exactly the semantics a backtracking parser wants and exactly what every hand-written regex loop gets subtly wrong.

One more control-flow subtlety separates Icon from every neighbor: every and while look alike but are not. while e re-evaluates e until it fails — its job is repetition. every e drives a generator, fetching the next result on each pass — its job is enumeration. every write(i to j) and while are the difference between "give me everything this can produce" and "keep doing this until it stops working." The distinction matters because an Icon programmer is always asking the same question: does this expression still have something to give?

Generators

If goal-directed execution is Icon's engine, the generator is its greatest export. In Icon, an expression doesn't evaluate to a value — it produces a result sequence: every value it could produce, yielded one at a time to whatever asked. find("the", s) doesn't return the first position of "the" and stop; it generates positions — 4, then 29 — and when it has no more to give, it fails. The every construct consumes a sequence:

s := "All the world's a stage. And all the men and women merely players"
every write(find("the", s))

Two lines, and every occurrence is printed — no index variable, no -1 sentinel, no loop bookkeeping. Where other languages' indexOf requires a three-parameter overload and a hand-rolled loop, Icon's generator simply keeps answering until it can't.

User procedures become generators with suspend, which yields a value and parks execution mid-procedure until resumption — a return that doesn't destroy state:

procedure ItoJ(i, j)
  while i <= j do {
    suspend i
    i +:= 1
  }
  fail
end

Call ItoJ(1, 5) under every and it yields 1, suspends; resumes, yields 2; and so on, until fail ends the sequence. Add the alternator | — which looks like or but actually generates its operands in turn — and to for integer ranges, and iteration collapses to intent:

every write(1 to 10)
every i := (1 | 3 | 4 | 5 | 10 | 11 | 23) do write(i)
every x := ItoJ(0,10) & x % 2 == 0 do write(x)    # evens only
How a generator drives a loop: find() yields results one at a time; every consumes them; &fail ends the loop cleanly
How a generator drives a loop: find() yields results one at a time; every consumes them; &fail ends the loop cleanly

If this sounds like Python's yield, that's because it is. When Python adopted generators in PEP 255 (2001), its authors listed Icon among the direct inspirations — the mechanism a generation of Python programmers know as laziness was running in Tucson two decades earlier. The same DNA surfaces in Jq's stream semantics and the Icon-descended Goaldi. Generators are now the standard answer to "iterate without materializing"; Icon was the proof of concept, complete with the coroutine machinery (suspend/resume) that modern languages still wrap in iterators and async.[14]

String scanning

Icon's third pillar is the string scanning environment: s ? expr binds s as the subject for a block of string operations, with two implicit variables — &subject and &pos (the cursor) — doing the bookkeeping that string parsing always makes explicit. Inside ?, functions like tab (move the cursor), many (skip a run of a character set), upto (find the next member of a set), match (literal string at cursor), and pos (test cursor position) compose into parsers of startling brevity. Words from a line:

s ? {
    while not pos(0) do {
        tab(many(' '))              # skip blanks
        word := tab(upto(' ') | 0)  # grab up to the next blank or end
        write(word)
    }
}

The same machinery that powered SNOBOL4 patterns — success, failure, cursor backtracking — is all here, just recast in functions on an implicit subject instead of a pattern datatype. An Icon string scanning block for a real grammar (the canonical example parses date strings like "Mon Dec 8" with a twenty-line matcher) is the lineal descendant of SNOBOL's BNF-as-pattern, traded down in raw power for a large gain in readability.

The payoff shows most clearly in the classic utility program — a word-frequency counter, the kind of thing awk people write to show off. In Icon the whole job is twenty lines and most of it is the sorting:

procedure main()
    counts := table(0)                     # default value 0 for new keys
    every line := !&input do {             # generator reads the stream
        line ? while tab(upto(&letters)) do {
            counts[tab(many(&letters))] +:= 1
        }
    }
    pairs := []
    every word := key(counts) do push(pairs, [word, counts[word]])
    every p := !pairs do write(right(p[2],6), "  ", p[1])
end

table(0) is a map whose missing keys default to zero; key generates the table's keys; the scanning block walks each line pulling alphabetic words. No regex literals, no split/join ceremony — the same job that takes a page in most languages' standard style is a paragraph here, and the paragraph is still readable.

Structures and strings

Icon's collections were equally prescient: lists usable as arrays, stacks, and queues; tables — the associative arrays McIlroy forced into SNOBOL4, here a first-class citizen; sets with union ++, intersection , difference --; and csets**, character sets like &digits, &lcase, and user-defined 'aeiou', built for the scanning operations. Strings are indexable between characters (position 1 is before the first character, position 0 after the last), sliceable from either end, and mutable through their subscripts — s[2] := "123" inserts into the middle of "abc". Everything iterable is a generator, down to !list producing a list's elements and !"Hello" producing a string's characters. Even &input — standard input — is a generator: every push(lines, !&input) reads a whole stream into a list in one expression.

For completeness, Icon also shipped co-expressions — first-class coroutine objects that capture a suspended computation and can be resumed explicitly with @. Generators get their values for free, in lexical order; a co-expression gets them on demand, from wherever you like, making it the general mechanism beneath suspend and the direct ancestor of the coroutine/yield machinery modern languages expose directly. It is one more case of Icon quietly shipping in 1978 what other languages would spend the next four decades rediscovering piecemeal — first as iterators, then as generators, then as async.

SNOBOL4 and Icon side by side

SNOBOL4 (1967)Icon (1978)
SurfaceColumn-format, labels and :S/:F transfersALGOL/Pascal-flavored blocks, procedure, :=
Control modelsuccess/failure branchingsuccess/failure everywhere — goal-directed
Pattern facilitypatterns as first-class data, full context-free powerstring scanning: ?, &subject, &pos, tab/many/upto
Iterationmanual loops via transfersgenerators — every, to, `, !, suspend`
Datastrings, numbers, arrays, tables, DATA recordslists, tables, sets, csets, records, co-expressions
The trademaximum expressive powermost of the power, dressed for the structured-programming era

The two are not rivals but stages of one idea: SNOBOL4 proved that matching and failure could be a programming language; Icon proved that idea could wear the clothes of a normal one.

Criticisms

An honest account has to include what went wrong. Laurence Tratt's 2010 analysis of Icon's design is the standard critical text, and its two main findings are instructive.[15]

First, the default-fail convention: a procedure that runs off its end returns &fail. Elegant for generators, it makes x := f(-1) a silent no-op — x keeps its old value, no warning — and Tratt found the vast majority of real Icon procedures are not generators, so the language's default behavior optimizes for the minority case while creating a subtle trap in the majority.

Second, the absence of Boolean logic creates edge cases of its own: if c then ... succeeds even when c was never assigned, because an unassigned variable's value (&null) is still a value — so the test must be written if /c then ... or c === &null. Icon traded Boolean complexity for failure propagation, and mostly won — but not everywhere, and not free.

The fair summary is the one Icon's own community reaches: for the domain it was built for — strings, scanning, search — goal-directed code is shorter, clearer, and harder to get wrong than anything before or since. For general-purpose programming, the same rules occasionally surprise. The idea was too good for its medium.

Unicon and today

Icon's lineage continues. Unicon (from Idol, the 1996 object-oriented extension) adds objects, networking, databases, and concurrency to the core language and remains actively developed. The reference Icon implementation itself is still maintained — release 9.5.25a shipped in September 2025, forty-seven years after the language was designed. SNOBOL4 runs wherever CSNOBOL4 compiles; Griswold's implementation and books remain available; and the University of Arizona keeps the Icon project pages that the language's researchers built. These languages are not specimens under glass. They compile, they run, and their maintainers still ship releases.

Running it today

Every implementation mentioned here is free:

  • SNOBOL4 — CSNOBOL4 (BSD-licensed port of the Bell Labs original, builds anywhere C exists), Macro SNOBOL4 (Phil Budne's portable C implementation), SPITBOL (GPL since 2009, the fastest by far), and the faithful Minnesota SNOBOL4 for PC-era fidelity. The clearinghouse is snobol4.org; the preservation mirror is regressive.org/snobol4.
  • Icon — the reference implementation from the University of Arizona Icon project (www.cs.arizona.edu/icon), plus Jcon for the JVM. The Griswolds' The Icon Programming Language (3rd ed., 2002) is the book, and the Arizona site hosts the documentation set.
  • Unicon — unicon.org, for Icon with objects, POSIX facilities, and a standard library the original never needed.

The classic texts remain findable: the "green book" — Griswold, Poage & Polonsky, The SNOBOL4 Programming Language (1968) — Griswold's The Macro Implementation of SNOBOL4 (1972) for the virtual-machine internals, Gimpel's Algorithms in SNOBOL4 (1976), and Hockey's SNOBOL Programming for the Humanities (1985) for the period's applied tradition. Griswold's own "A History of the SNOBOL Programming Languages" (1978) and the HOPL volume chapter are the primary-source history — this article leans on them throughout.

Language history: what the line taught us

Placed end to end, the SNOBOL–Icon story is a compressed history of how programming-language ideas actually travel. A concept appears (COMIT's rewrite rules), is perfected in a form the mainstream can't absorb (SNOBOL4's pattern datatype on a 1967 mainframe), is rediscovered in diluted form by fashionable successors (AWK's patterns, Perl's regexes), and is finally re-embedded so quietly that its users never learn where it came from (Python's yield, jq's streams, every parser-combinator library on Earth).

There is a subtler lesson in the lineage, too: ideas persist better than implementations. SNOBOL4 the artifact is a curiosity — column-format, mainframe-bound, its idioms extinct. But the idea the artifact carried turned out to be load-bearing. It survived a syntax change (Icon), survived being renamed (generators), survived being diluted (regex), and surfaced again every time the industry rediscovered that text is most of what computers actually process. When Lua's designers wrote their HOPL history, they listed SNOBOL among their language's influences — the pattern tradition reaching even the embeddable-scripting niche by way of its reputation. When Stephen Bourne needed a Unix shell scripting language in the same Bell Labs building where SNOBOL was made, the result, bs, borrowed SNOBOL-flavored features outright. The family touches nearly every string-handling idiom in daily use.

Three of the modern programmer's daily tools descend directly from this family:

  • Pattern matching — SNOBOL4 defined the problem space regular expressions still occupy, and its context-free power remains beyond stock regex forty-five years later.
  • Generators — Icon's suspend/resume is Python's yield, and the lazy sequence is now how the industry thinks about iteration.
  • Goal-directed evaluation — success/failure as a control primitive previews today's result types and early-return styles (Result in Rust, err == nil in Go) — the same instinct: make failure a value, and let the program steer by it.

The languages themselves, meanwhile, simply persisted — maintained, ported, free, and still taught to anyone willing to look back. Text didn't stop needing processing in 1967, and the tools Bell Labs and Tucson built for it have never actually been improved upon at the things they were built for.

And one more thing persists: the record itself. Griswold wrote his history in 1978, while the story was still warm. The green book is still readable. The SPITBOL source still compiles. The Arizona Icon pages still serve. SNOBOL and Icon are among the best-preserved languages of their generation — documented by their own authors, in their own words, with the source still runnable. That is what preservation looks like when it works. Knowledge is only ever lost when the world stops looking — and pages like this one exist to make sure it doesn't.

See also

Footnotes

  1. ↑ PEP 255, "Simple Generators" (Schemenauer, Peters, Hetland, 18 May 2001), lists Icon among the generators' direct inspirations.
  2. ↑ Ralph E. Griswold, "A History of the SNOBOL Programming Languages", ACM SIGPLAN Notices 13:8 (August 1978), and the HOPL paper Griswold (1981) — the standard primary sources on SNOBOL's origins.
  3. ↑ David Farber, posting to his Interesting People mailing list, 26 December 2008 — the first-person account of the SEXI card and the snowball's chance. The canonical backronym appears in the Encyclopedia of Computer Science and Technology, vol. 13 (1979).
  4. ↑ Ralph E. Griswold, The Macro Implementation of SNOBOL4 (W.H. Freeman, 1972) — the definitive account of the SIL virtual machine. McIlroy's second contribution came in 1969, when he insisted the language gain the associative-array "table" type.
  5. ↑ SNOBOL4's datatype system and single garbage-collected heap — Griswold, Poage & Polonsky, The SNOBOL4 Programming Language (Prentice Hall, 1968), the canonical "green book."
  6. ↑ "Dr. Dobb's: Programs That Transform Their Own Source Code; or: the Snobol Foot Joke" — the EVAL/CODE self-modification tradition.
  7. ↑ James F. Gimpel, "A Theory of Discrete Patterns and their Implementation in SNOBOL4", Communications of the ACM 16:2 (February 1973), 91–100 — the formal treatment establishing that SNOBOL4 patterns subsume context-free grammars.
  8. ↑ The recursive-pattern gap: SNOBOL4 (1967) vs. Perl 5.10's (?R) recursion (December 2007); Gimpel 1973 supplies the theory.
  9. ↑ Susan M. Hockey, SNOBOL Programming for the Humanities (Clarendon Press, 1985) — the humanities-computing standard text; also Gimpel's Algorithms in SNOBOL4 (Wiley, 1976) and Griswold's String and List Processing in SNOBOL4 (Prentice Hall, 1975).
  10. ↑ Gimpel's SITBOL course implementation (1972, Stevens Institute of Technology) and SPITBOL's history through its 2009 GPL release.
  11. ↑ Ralph E. Griswold and David R. Hanson, "An Overview of SL5", ACM SIGPLAN Notices 12:4 (April 1977), and Griswold & Griswold, The Icon Programming Language, 3rd ed. — on SL5's lessons and Icon's design constraints.
  12. ↑ Griswold on the naming in a 1985 interview — the 'icon' term collision with the GUI usage from Xerox PARC.
  13. ↑ Icon's goal-directed model per Griswold & Griswold, The Icon Programming Language, 3rd ed. (2002), and Laurence Tratt's retrospective analysis (2010).
  14. ↑ PEP 255 naming Icon as an inspiration for Python's generators; Icon's suspend/resume as user-level coroutines — Griswold & Griswold 2002.
  15. ↑ Laurence Tratt, "Experiences with an Icon-like expression evaluation system" (2010) — the standard design critique.
This page was last edited 2026-10-20 12:46:25 UTC by ALB Team. What links here