Cool
The Classroom Object-Oriented Language, a deliberately small statically typed OO language Alex Aiken designed so undergraduates could write a complete, real compiler in a single term.
Created by Alexander Aiken (University of California, Berkeley; later Stanford University)
Cool - the Classroom Object-Oriented Language - is a small statically typed object-oriented language designed by Alexander Aiken for a single purpose: to be the language an undergraduate compiler course project compiles. It is not a language anyone ships production software in, and it was never meant to be. Its design goal was to sit precisely on the line where a language is rich enough to force students to confront the real problems of compilation - inheritance, dynamic dispatch, a non-trivial type system, garbage collection, runtime representation of objects - while staying small enough that one student, in one term, can implement all of it and get working machine code out the other end.
That balance is why Cool has outlived most teaching languages. Aiken introduced it in “Cool: a portable project for teaching compiler construction,” published in ACM SIGPLAN Notices volume 31, issue 7 in July 1996, and it has been the project language for compilers courses at Berkeley, Stanford, and a long list of other institutions ever since.
History and Origins
Aiken designed Cool while on the faculty at the University of California, Berkeley, where it was first used in the CS 164 programming languages and compilers course. The motivation described in the 1996 paper is a familiar problem in CS education: the compiler course is a fixture of the undergraduate curriculum, nearly every program includes a substantial implementation project, and nearly every instructor either invents a throwaway toy language or inherits an undocumented one from a predecessor. Toy languages tend to be too small to teach anything interesting; real languages are far too large to implement in a single term.
Cool was the answer, and crucially it shipped as a project, not just a language definition. The distribution bundles a reference manual, a set of staged assignments, a reference compiler, regression tests, and a runtime - the “portable project” of the paper’s title. Instructors get a complete course; students get a specification precise enough to code against and a reference implementation to compare their output with.
When Aiken moved from Berkeley to Stanford in 2003, Cool moved with him and became the basis of the CS 143 compilers project. The reference manual in the Stanford distribution carries a copyright of 1995-2000 by Alex Aiken, and the language definition has been essentially stable since. Adapted editions of the manual - one modified by Wes Weimer, dated 1995-2006, is widely circulated - are used at other schools.
Cool also acquired an academic offshoot. In 2004, Bor-Yuh Evan Chang and George Necula at Berkeley published the Coolaid Reference Manual, describing Coolaid: an assembly-level type-checking tool for Cool compiler projects built on Berkeley’s Open Verifier infrastructure, which used the language as a compact but realistic target for verification of generated code.
Design Philosophy
Cool’s design is best understood as a series of deliberate subtractions from a Smalltalk- or Java-like object model, each justified by “does implementing this teach the student something new?”
Everything is an expression. Cool has no statements. if, while, let, case, and blocks all produce values and have types. This keeps the abstract syntax tree small and the type checker uniform, and it forces students to think in terms of typing judgments rather than ad-hoc statement rules.
Single inheritance, nominal typing. Every class except Object inherits from exactly one parent, and the inheritance graph must be a tree - no cycles, no multiple inheritance, no interfaces. This gives students a real subtype relation to implement (with least upper bounds needed to type if and case) without dragging in the complexity of a lattice.
A type system with one genuinely hard feature. Cool is otherwise conventional, but it includes SELF_TYPE, a type that denotes the dynamic type of the receiver. SELF_TYPE makes inherited methods like a copy that returns a properly typed object type-check correctly in subclasses. It is the part of the assignment where students discover that a type checker is more than a tree walk, and it is Cool’s most-discussed feature.
Automatic memory management. Objects are heap-allocated and garbage-collected. Students who write the code generator have to lay out objects, maintain the information the collector needs, and think about what the runtime is entitled to assume.
No escape hatches. There are no arrays, no pointers, no explicit deallocation, no exceptions, no modules, no generics, no first-class functions, and no separate compilation. Data structures are built out of classes and inheritance, which is exactly the exercise the language wants students doing.
Key Features
A Cool program is a sequence of class definitions. Each class defines attributes (instance variables, always private to the object) and methods (always public), and inherits everything from its parent.
class List inherits IO {
head : Int;
tail : List;
init(h : Int, t : List) : List {
{
head <- h;
tail <- t;
self;
}
};
print_all() : SELF_TYPE {
{
out_int(head);
out_string("\n");
if (isvoid tail) then self else tail.print_all() fi;
self;
}
};
};
class Main inherits IO {
main() : Object {
(new List).init(1, (new List).init(2, (new List).init(3, new List))).print_all()
};
};
Notable elements of the language:
| Feature | Notes |
|---|---|
| Basic classes | Object, IO, Int, String, Bool are predefined. Int, String, and Bool may not be inherited from; IO and Object may be. |
| Dispatch | expr.method(args) for dynamic dispatch; [email protected](args) for static dispatch, which starts method lookup at a named ancestor class. |
SELF_TYPE | Denotes the dynamic type of self; usable as a method return type, attribute type, and in new SELF_TYPE. |
case | case expr of x : Type => ... esac performs a runtime type test, selecting the branch whose declared type is the closest ancestor of the expression’s dynamic type. |
let | Introduces one or more bindings with optional initializers, scoped over a body expression. |
isvoid | Tests whether a reference is void - Cool’s equivalent of a null check. |
| I/O | Provided entirely by the IO class: out_string, out_int, in_string, in_int. Programs get I/O by inheriting from IO or holding an IO object. |
| Entry point | Execution begins by creating an object of class Main and invoking its main method. |
The reference compiler, coolc, emits MIPS assembly, which students run under the SPIM simulator rather than on real MIPS hardware. The 1996 paper presents the project as portable, and the support code has historically been distributed for Unix-like systems; the course materials have generally let students implement the assignments in C++ or Java.
Evolution
Cool’s most striking property is how little it has changed. The language was designed once, documented precisely, and then left alone - which is the right decision for a teaching artifact, since a course project’s specification is only useful if it is stable and unambiguous. The reference manual’s copyright range - 1995-2000 in the Stanford distribution, extended to 2006 in Wes Weimer’s adapted edition - covers the period of active revision; since then the changes have been to courses and course materials rather than to the language.
What has evolved is the delivery. The recorded version of Aiken’s compilers course, released through Stanford’s free online course efforts around 2011-2012 and distributed via OpenClassroom, Coursera, and Stanford Online, gave Cool an audience far larger than any lecture hall. The result is a substantial body of independently written Cool compilers on GitHub, in languages including Java, Go, C, and Python, a number of which target LLVM IR or JVM bytecode rather than the original MIPS.
Cool also has a visible successor. In 2019, Rohan Padhye, Koushik Sen, and Paul Hilfinger presented ChocoPy at SPLASH-E - a statically typed subset of Python 3 built for Berkeley’s compilers course, designed in response to the tradeoffs of purpose-built classroom languages like Cool. ChocoPy’s argument is that students engage more with a language whose syntax they already know; Cool’s counter-argument, implicitly, is that a purpose-built language can be specified exactly and contains nothing that is not pedagogically load-bearing.
Current Relevance
Cool is dormant as a language in the sense that nobody is adding features to it, but it is far from dead. The Stanford distribution and reference manual remain online, the course that uses it is still taught and still freely available, and Cool is still a frequent answer to “what language should I write a compiler for?” among self-taught systems programmers. Its ecosystem is not libraries and package managers - it is a corpus of student compilers, each one a complete implementation of the same well-specified language.
For anyone learning compilers, that corpus is unusually valuable. Because every implementation targets the same specification with the same staged assignments and the same regression tests, it is possible to compare approaches to parsing, type checking, and code generation directly, on a language small enough to hold in your head.
Why It Matters
Cool matters not for what has been written in it but for what has been written because of it. It is a case study in designing a language for a purpose other than production use, and in doing that job well: small enough to finish, large enough to hurt in the places that teach, and specified precisely enough that a student’s compiler can be checked against a reference.
The features Aiken chose to keep - inheritance with dynamic dispatch, a subtype relation with least upper bounds, SELF_TYPE, garbage collection, runtime type tests - are precisely the ones that separate a calculator compiler from a real one. A great many programmers first understood what a type checker actually does, or what an object looks like in memory, by implementing them for Cool. That is a larger legacy than most languages with real user bases can claim.
Timeline
Notable Uses & Legacy
Stanford CS 143 - Compilers
Stanford's undergraduate compilers course uses Cool for its multi-part project: students build a lexer, parser, semantic analyzer with full type checking including SELF_TYPE, and a code generator emitting MIPS assembly for the SPIM simulator.
UC Berkeley CS 164
Berkeley's programming languages and compilers course was the first home of Cool, and generations of Berkeley students wrote Cool compilers before the course later moved to other project languages.
Stanford Online / Coursera Compilers MOOC
Aiken's Compilers course put Cool in front of a global audience of self-taught programmers. The optional project - a complete Cool compiler - became one of the best-known "write a real compiler" exercises available outside a university.
Compiler courses at other universities
Cool and adapted variants of its reference manual have been used well beyond Stanford and Berkeley. Course sites hosting Cool manuals include the University of Virginia (CS 415), the University of Michigan (EECS 483), and the University of Delaware (CISC 672).
Independent Cool compilers and runtimes
Because the language is small but non-trivial, Cool is a common target for hobby compiler projects. Publicly available implementations reportedly include compilers targeting LLVM IR and JVM bytecode, interpreters written in C and Python, and numerous MOOC coursework repositories on GitHub.