Est. 2002 Advanced

GOO

A dynamic, type-based, object-oriented language from the MIT AI Lab - Jonathan Bachrach's attempt to build a simpler, lisp-syntaxed Dylan that compiled itself to C on the fly.

Created by Jonathan Bachrach, MIT AI Lab (later MIT CSAIL), with contributions from James Knight, Andrew Sutherland, Eric Kidd and Greg Sullivan

Paradigm Multi-paradigm: object-oriented via generic functions and multiple dispatch, functional with first-class closures, and metaprogramming through pattern-matching macros and compile-time evaluation
Typing Dynamic and strong, but type-based: types are first-class runtime values, and optional type annotations on parameters, results and slots both document intent and drive method dispatch
First Appeared 2002
Latest Version 0.155, the final upstream snapshot, whose changelog entry and repository commit are dated 19 November 2003. Debian still packages it, most recently as 0.155+ds-6 in May 2025

GOO - the name is an acronym for Generic Object Orientator - is a dynamic, type-based, object-oriented programming language built by Jonathan Bachrach at the MIT AI Lab in the early 2000s. Its own documentation describes the ambition with unusual precision: GOO “attempts to be a simpler lisp-syntaxed Dylan, an object-oriented Scheme, and a lispified Cecil,” aiming to “offer the best of both scripting and delivery languages while at the same time incorporating an extreme back-to-basics philosophy.”

That is a very specific place to stand. Dylan had a rich object model and a serious compiler but a heavy syntax and a heavy toolchain. Scheme had beautiful minimalism and no object system worth the name. Cecil had the most interesting dispatch semantics of the three and almost no users. GOO tried to take the object model from the first, the syntax and size from the second, the dispatch ideas from the third, and end up with something you could start in a REPL and still ship.

A note on dating. GOO is sometimes listed with a first-appearance year in the early 1990s. The primary record does not support that. The project’s own source repository begins on 19 April 2001, under the earlier name Proto; the rename to GOO appears in commits dated 13-15 March 2002; and the first Debian upload follows in May 2002. This page uses 2002 as the year GOO appeared under that name, with 2001 as the start of the work.

History and Origins

The Dylan years

Bachrach spent 1994 to 1999 at Harlequin working on Dylan, and then a further year at Functional Objects, the spin-off that took the Dylan compiler commercial. Dylan is the essential prior context. It is a language with CLOS-derived generic functions and multiple dispatch, a sealing discipline that lets a compiler devirtualise calls it can prove are closed, and - after its early Lisp-syntax phase - an ALGOL-style infix surface syntax adopted to look less alien to mainstream programmers.

Two things about that experience shaped GOO. First, Bachrach had already worked out, with Keith Playford, how to keep Lisp-grade macro power in a language with conventional syntax - the 1999 “D-Expressions: Lisp Power, Dylan Style” report, and later the OOPSLA 2001 paper on the Java Syntactic Extender, which did the same trick for Java. Second, he had seen how much machinery a Dylan implementation required. GOO is in large part a reaction: keep the object model, drop the syntax, drop the weight.

Proto, 2001

The project starts on 19 April 2001 as Proto, bootstrapped from an emulator written in Dylan itself - the repository still contains that emulator as a set of .dylan files with an Open Dylan project descriptor. By 10 May 2001 the commit log records “proto v0.82 bootstrapped!”, meaning the language could compile itself and the Dylan scaffolding could be retired.

The Proto manual of 20 September 2001 is remarkably candid about the state of the implementation:

Proto is pretty slow at this point. I’m using an AST-based interpreter. This will improve in coming releases. There is not a large amount of debugging support. In particular, there is no backtrace facilities.

Bachrach presented the work that year at the first Lightweight Languages conference at MIT, in a talk that paired it with the Java Syntactic Extender under the heading “Rethinking Lightweight Languages.”

Becoming GOO, 2002

In March 2002 the project renames itself. The commit log tells the story in three lines - “goo first cut” on 13 March, “goo v114” on 14 March, “proto2goo” and “goo release script” on 15 March - and a proto2goo.txt file in the repository catalogues everything that was added, removed or renamed in the transition. Two months later, on 18 May 2002, Debian accepted the first goo package.

The name change also freed the word “Proto,” which Bachrach reused years later for an entirely different language - the spatial-computing language he developed with Jacob Beal for programming sensor networks and swarms. The two are unrelated apart from their author.

Design Philosophy

Type-based, not type-checked

The single most distinctive idea in GOO is captured in the phrase it uses about itself: it is a type-based language. Types are ordinary first-class runtime values. You can compute with them, pass them around, and construct new ones with combinators:

  • (t+ a b) builds a union type
  • (t< <class>) builds a subclass type - the type of classes descending from a given class
  • (t= value) builds a singleton type matching exactly one value
  • (t? x) is (t+ x (t= #f)) - the ubiquitous “x or false” optional type

Annotations are optional and are written with a vertical bar: x|<int>. They appear on parameters, on return values after a => marker, and on slots. They are not a static type system - GOO is dynamically checked - but they are not merely documentation either, because they are exactly what method dispatch uses.

Everything dispatches

There are no methods-in-classes. As in CLOS, Dylan and Cecil, GOO has generic functions with multiple dispatch: a generic is declared with dg, methods are added to it with dm, and the method chosen at a call site depends on the runtime types of all the arguments, not just the first. next-method walks the applicable chain.

Because dispatch is by type and types include unions and singletons, a great deal that other languages express with if chains is expressible as method specialisation instead.

Small vocabulary, terse names

GOO takes brevity to a degree that is initially startling. Definitions are two-letter forms - dc class, dm method, dg generic, df function, dv variable, dp property, ds macro. Special forms are three letters: fun, let, loc, lab, fin, seq, rep. Classes are conventionally bracketed, <int>, <str>, <col>.

The project’s own proposal files show this was contested. DEFINITIONS.TXT opens: “current definition special form names are unpronouncable as words. also the definition doesn’t look like the usage” - filed as an open issue against the language by its own author.

Key Features

Syntax by example

A fragment from the bank demo in the source tree shows most of the language at once:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
(use goo)

(dc <account> (<any>))
 (dp balance (<account> => <int>) 0)

(dc <checking-account> (<account>))
(dc <savings-account> (<account>))

(dv *minimum-balance* 100)

(dm credit (account|<account> amount|<int>)
  (opf (balance account) (+ _ amount))
  #t)

(dm can-handle-debit? (account|<account> amount|<int> => <log>)
  (>= (balance account) amount))

(dm transfer (from|<account> to|<account> amount|<int> => <log>)
  (when (and (> amount 0) (can-handle-debit? from amount))
    (debit from amount)
    (credit to amount)))

dc declares a class with its direct parents. dp declares a property with its type and default. dm adds a method, whose parameters carry |type specialisers and whose return type follows =>. <log> is the boolean class. opf is the operate-and-update macro; the _ is the placeholder for the current value, so (opf (balance account) (+ _ amount)) is the equivalent of balance += amount while going through the setter.

The core is genuinely small

The whole special-form vocabulary fits on a page: quote, if, seq, set, fun, let, loc, lab, fin, dv, dm, dg, dc, isa, slot, ds, ct, macro-expand, next-method, use, export. Everything else - df, and, or, when, select, case, rep, try, inc - is a macro over that core. The manual annotates each form with its ancestor: seq is Scheme’s begin, loc is letrec, lab is Dylan’s block/return, fin is Dylan’s block/cleanup and Common Lisp’s unwind-protect.

Macros

Macros are defined with ds and written as quasiquoted pattern-and-template pairs, in the destructuring style Bachrach had explored in Dylan and Java:

1
2
(ds (when ,test ,@body)
  `(if ,test (seq ,@body) #f))

ct evaluates its body at compile time so that macro expansion can depend on computed values, and macro-expand exposes the expander. The macros were unhygienic during the language’s active life - the changelog and bug list both carry the item “document that macros are unhygienic at present,” and hygiene appears on the to-do list rather than in the implementation.

Dynamic compilation to C

GOO ships two front ends: goo, which defaults to AST interpretation, and g2c, which defaults to translating expressions into C and compiling them dynamically. Either mode can be selected at runtime with the GOO_EVAL_MODE environment variable or with the ,g2c-eval and ,ast-eval REPL commands. This is the “Simple Dynamic Compilation” of the 2002 Harvard talk, and it is the project’s answer to the slowness Bachrach had flagged in the 2001 Proto manual: keep the interactive interpreter for development, generate C for delivery, without changing the source.

The optimisation notes in the repository list what the compiler actually did - self-recursive call detection, dynamic-extent analysis, a dispatch cache, stack allocation, inlined primitives - alongside a longer list of things that were still wanted. No published benchmark accompanies these, and the project never made a quantitative performance claim; the honest summary is that GOO aimed at delivery-grade performance and got far enough to run real-time MIDI code, not that it was measured against anything.

The runtime

The runtime is C, garbage-collected with the Boehm conservative collector, with threads and locks built on POSIX threads and a corresponding event layer. Bignum arithmetic arrived last, in 0.155, via GMP. The lightweight C embedding facility added in 0.154 lets C text be written directly inside GOO source through c-ment and c-expr forms and the #{} and #" "# reader syntaxes, so bindings could be written without a separate interface-definition step.

Modules are handled by use and export at file granularity. The project’s own proposal files debated richer designs - MODULES.TXT, SIMPLE-MODULES.TXT, DYNAMIC-OVERLOADING.TXT, PARAMTYPES.TXT - and most of them remained open when work stopped.

Evolution

The version history is dense and short. Roughly seventy-eight numbered releases are recorded in the changelog, running from the Proto 0.8x series in 2001 through the 0.1xx series that carried the GOO name. Development pace over 2002 is brisk: the roughly forty versions between 0.114 in March 2002 and 0.153 in January 2003 work out closer to a release a week than a release a fortnight.

VersionDateSignificance
0.82May 2001Proto bootstraps itself, retiring the Dylan-based emulator
0.101August 2001Type-based aliases t+, t<, t= for union, subclass and singleton specialisers
0.102September 2001The Proto manual, the first substantial public description
0.114March 2002First cut under the name GOO
0.133May 2002The version first packaged for Debian
0.153January 2003Last release described as stable
0.154November 2003Lightweight C embedding: c-ment, c-expr, to-c, new reader syntaxes
0.155November 2003Bignum support via GMP; the final upstream snapshot

After 0.155, upstream work stops. Bachrach’s 2004 Lightweight Languages talk on Gooze, a multimedia stream processing language, is the visible successor of the real-time-media thread that ran through GOO from the beginning, but GOO itself received no further releases.

Current Relevance

GOO is dormant, and has been for over two decades. There is no active mailing list traffic, no package ecosystem, and no user community. The source lives on GitHub under the googoogaga organisation - the name of the project’s old mailing list and domain - as an archive of the CVS-era history, GPL v2 licensed, its last commit dated 19 November 2003.

What is genuinely unusual is that it still runs. Debian has packaged goo continuously since May 2002, and and as of the May 2025 upload the package is present as 0.155+ds-6, with maintenance work as recent as that date fixing threading behaviour under GCC 15. For anyone wanting to try the language, installing the Debian package inside a container is far less work than building the 2003 source against a modern compiler. No official or community Docker image exists.

The documentation that survives is better than the language’s obscurity would suggest: a reference manual, an introduction, and lecture decks on the implementation and on the bootstrapping process, all still hosted on Bachrach’s MIT CSAIL pages.

Why It Matters

It is a careful subtraction from Dylan. Most language design proceeds by addition. GOO went the other way: take a design its author knew intimately from six years of professional work, identify what was essential - the generic-function object model, multiple dispatch, first-class types, macros - and discard the rest, including the infix syntax that had been Dylan’s most visible break with its Lisp ancestry. The result is one of the cleanest available demonstrations of what a CLOS-family object model looks like once everything else is stripped away.

It took first-class types seriously. The t+/t</t= combinators, and the t? optional type built out of them, give a dynamic language a compositional vocabulary for describing what a parameter accepts - unions, singletons, subclass-of - without a static type checker. Optional gradual annotations that participate in dispatch rather than merely in checking remain a comparatively rare design point.

Its two-mode execution model prefigured a now-standard idea. Interpret for interactivity, compile natively for delivery, switch between them with an environment variable, and keep one source language for both. That combination is now routine in dynamic language runtimes; in 2002, doing it by generating C and invoking the system compiler at runtime was a pragmatic and instructive way to get there on a research budget.

It is a complete, legible artefact. A small runtime, a self-hosted compiler, a bootstrap path documented in its own lecture notes, some seventy-eight changelogged releases, an open list of unresolved design proposals filed by the author against his own language, and a package that still builds. As a specimen for studying how a dynamic object-oriented language is actually built - rather than how a finished one is used - GOO is more useful than most languages a hundred times its size.

Sources

Timeline

1994
Jonathan Bachrach joins Harlequin, where he works on Dylan until 1999, then continues at the Dylan spin-off Functional Objects until 2000. Nearly every design decision in GOO traces back to this period - the generic-function object model, the sealing-and-dispatch machinery, and a first-hand view of what made Dylan heavy
2001
On 19 April 2001 Bachrach makes the initial source import of the project at the MIT AI Lab. The language is called Proto at this stage, is bootstrapped from an emulator written in Dylan, and reaches a self-hosting milestone in May with version 0.82
2001
The Proto manual, version 0.102, is dated 20 September 2001. Its opening line - "a new dynamic type-based object-oriented language ... meant to be simple, productive, powerful, extensible, dynamic, efficient and real-time" - survives almost verbatim into every later description of GOO. Bachrach presents the work at the first Lightweight Languages conference at MIT the same year, in a talk covering the Java Syntactic Extender and Proto
2002
The rename lands in March 2002: repository commits from 13-15 March read "goo first cut", "proto2goo" and "goo release script", and version 0.114 on 14 March is the first cut under the new name. GOO stands for Generic Object Orientator
2002
Debian accepts the first goo package, version 0.133-1, on 18 May 2002, uploaded by Jonathan Hseu. GOO is thus installable through a mainstream package manager within two months of acquiring its name
2002
Bachrach gives "Simple Dynamic Compilation with GOO" as a computer science colloquium at Harvard, describing the g2c approach of translating GOO to C and compiling it dynamically at runtime rather than interpreting an AST
2003
Version 0.153, dated 16 January 2003, is the last release the project describes as stable. The website continues to list it alongside the two later test versions for the rest of the project's life
2003
"Alien Goo: A Lightweight C Embedding Facility" is presented at the MIT Dynamic Languages Seminar and at a UCSD Center for Research in Computing in the Arts colloquium. Version 0.154 implements it: c-ment and c-expr forms, the #" "# and #{} reader syntaxes, and a to-c protocol that let C be written inline in GOO source
2003
The final upstream activity is dated 19 November 2003 - version 0.155, adding bignum arithmetic through the GMP library, and reference manual v46 carrying the same date. Roughly seventy-eight numbered releases are recorded in the changelog across about two and a half years
2004
Bachrach presents "Gooze: A Multimedia Stream Processing Language" at the Lightweight Languages 4 conference at MIT. His research attention moves on - to spatial and amorphous computing, and eventually to hardware construction languages at Berkeley - and GOO itself sees no further releases
2025
The Debian package remains alive under Aaron M. Ucko, reaching 0.155+ds-6 in May 2025 with fixes for threading under GCC 15. More than two decades after upstream stopped, a twenty-year-old research language still builds against a current toolchain

Notable Uses & Legacy

Real-time MIDI music software

The source tree carries a music subsystem - beatbox.goo, instruments.goo, rhythms.goo, midi.goo and a win32 MIDI backend over a C shim - plus an electrobeep demo built on top of it. This is where the "real-time" goal in the language's mission statement came from: Bachrach wanted to write live music software in a dynamic language, which sets hard constraints on allocation and dispatch cost

SamurUI, a GTK-based user interface layer

A GUI toolkit written in GOO over SWIG-generated GTK bindings, including a graph widget, a treeview binding backed by hand-written C, and callback plumbing. It was the project's proof that the foreign-function interface was good enough to drive a real C library rather than only toy examples

Sensor-network mote tooling

A nest subtree contains a mote abstraction, serial communication over a libezv24 binding, and a threaded demo that pipes mote data into the SamurUI graph widget. It reflects the MIT AI Lab work on networked embedded systems that surrounded the language, and it exercised GOO's threads, its pipe collections and its C bindings simultaneously

Interpreters written in GOO

The tree ships a small BASIC interpreter, a CPS interpreter, a virtual machine and a generic VM, all in GOO. Writing interpreters in the language was both a stress test of its dispatch and macro facilities and a nod to the tradition it came from - the same exercise every Scheme implementation uses to prove itself

Teaching material on dynamic language implementation

The documentation set includes lecture decks on GOO's implementation and its bootstrapping process alongside the reference manual and introduction, used in Bachrach's talks and, reportedly, in MIT teaching on the design and implementation of dynamic object-oriented languages. GOO's small, readable runtime made it a usable classroom specimen in a way that a production language is not

A continuously maintained Debian package

goo and its g2c compiler have been in Debian since May 2002 and, as of the May 2025 upload, are still present across the stable, testing and unstable suites. The package has been carried through more than twenty years of compiler and toolchain changes - most recently GCC 15 threading fixes - making it one of the easiest ways to run an abandoned research language on a modern machine

Language Influence

Influenced By

Running Today

Run examples using the official Docker image:

docker pull
Last updated: