Est. 1975 Intermediate

CLU

Barbara Liskov's MIT research language that was the first implemented language to support abstract data types directly, and that introduced iterators, checked parameterized types and a disciplined exception mechanism.

Created by Barbara Liskov, with Russ Atkinson, Craig Schaffert and Alan Snyder (MIT)

Paradigm Procedural with data abstraction (clusters, no inheritance)
Typing Static, Strong
First Appeared 1975
Latest Version Portable CLU 3.7 (November 2016)

CLU is a programming language designed at MIT by Barbara Liskov and her students between 1973 and 1979. It was the first implemented language to support abstract data types directly: a type is defined by the operations that can be performed on it, and the language guarantees that no other code can see how the type is represented. CLU was never widely used outside research and teaching, and its designers did not intend it to be. Its ideas spread anyway. Iterators with yield, exceptions that are part of a procedure’s declared interface, generic types checked at compile time, and multiple assignment all appear in CLU in forms that later languages adopted.

History and Origins

From modularity to abstract types

In 1972 Liskov was working on programming methodology, specifically on how to divide large programs into modules. She noticed that many of the modules described in the literature, including her own work on the Venus operating system, were really defining data types. This led to the idea of an abstract type: a set of objects together with a set of operations, whose representation is hidden from everything except those operations.

She presented the idea at a workshop in Savannah in April 1973 and then worked it out with Stephen Zilles, also at MIT, over the spring and summer. Their September 1973 paper said an abstract type would be implemented by a cluster, a module holding a description of the representation plus the code for all the operations. A later version of the paper, “Programming with Abstract Data Types”, appeared at the ACM SIGPLAN Symposium on Very High Level Languages in April 1974.

Liskov decided in spring or summer 1973 to build a complete language around clusters. In the fall of 1973 the language was named CLU, from the first three letters of “cluster”, and design work began in earnest. By then several basic choices had been made: types would be implemented by clusters, all objects would live in a garbage-collected heap, and type checking would be complete and static.

The design group

The four main designers were Liskov and three graduate students: Russ Atkinson, Craig Schaffert and Alan Snyder. Zilles was involved early on but moved to specification work by 1974. Bob Scheifler and Eliot Moss joined later. The group held weekly design meetings and recorded its decisions in internal design notes. There were 78 notes, from 6 December 1973 to 30 July 1979. Liskov led the project and made the final decisions; votes in design meetings were never binding.

The designers knew the existing languages well. Liskov described CLU’s semantic model as “largely borrowed from Lisp” and its syntax as Algol-like. Simula 67 was the closest existing language to what they wanted, but it did not enforce encapsulation or support user-defined generic types. The group chose not to adopt Simula’s inheritance, which Liskov called “a distraction from what we were trying to do”. She also said that Smalltalk, developed at the same time, was “completely unknown to us until around 1976.”

Implementation

Work on a compiler for a preliminary version, CLU .5, started in summer 1974. Snyder wrote the parser, Atkinson the code generator and Schaffert the type checker. The code generator first produced Lisp and later MDL, a Lisp dialect used at MIT. The compiler was first written in Lisp and soon rewritten in CLU, and it ran on the PDP-10. The CLU .5 reference manual was issued internally in January 1975. It covered all of CLU in some form except exceptions and iterators.

The rest of the language was designed by the end of 1976, and 1977 was spent reviewing and adjusting it. In 1977 the compiler was rewritten to generate macro-assembler, because compiling through MDL was slow. This meant the group had to write its own runtime system, garbage collector and debugger. A final design pass in 1979 added the resignal statement and own data, and the final reference manual was published in October 1979. By 1980 there was a compiler for the DECSYSTEM-20 good enough to give to other groups. It was later retargeted to the VAX and the Motorola 68000.

Liskov estimated that about fourteen person-years went into CLU between 1973 and the production compiler in 1980.

Which year?

The encyclopedia dates CLU to 1975. That is a reasonable date, but not the only one. The name and the design go back to fall 1973, and a compiler for CLU .5 existed in 1974. The first reference manual (January 1975), the exception mechanism (June 1975) and the iterator design (September 1975) all date from 1975. The first widely read description of the finished language, in Communications of the ACM, came in August 1977.

Design Philosophy

Liskov’s history says the main goal of the project was research on programming methodology, not a product. The group saw its main output as ideas and publications. “We did not think of CLU as a language that would be exported widely,” she wrote.

She listed the design principles the group applied deliberately:

  • Keep focused. Features unrelated to data abstraction were not investigated. Concurrency was planned at first and then dropped. It was taken up later in Argus.
  • Minimality. Features the designers were unsure about were left out. If users really needed them, they would complain.
  • Simplicity. A construct was simple if it and its interactions could be explained easily.
  • Expressive power. It should be easy to say what programmers needed to say.
  • Safety. Errors should be prevented or caught early. This is why CLU has a garbage-collected heap, complete static type checking and no implicit type conversions.

The designers also avoided things they disliked in other languages. They thought Pascal had made too many compromises for the sake of easy implementation, and that Algol 68 had gone too far with overloading and coercions. CLU therefore has no overloading at all.

Key Features

Clusters

A cluster defines a type. Its header lists the operations visible outside the cluster, and the rep line gives the hidden representation. Inside the cluster, the special type cvt converts between the abstract type and its representation, so only the cluster’s own code can see the representation.

intset = cluster is create, insert, member, elements

    rep = array[int]

    create = proc () returns (cvt)
        return (rep$new())
    end create

    insert = proc (s: cvt, x: int)
        for e: int in rep$elements(s) do
            if e = x then return end
        end
        rep$addh(s, x)
    end insert

    member = proc (s: cvt, x: int) returns (bool)
        for e: int in rep$elements(s) do
            if e = x then return (true) end
        end
        return (false)
    end member

    elements = iter (s: cvt) yields (int)
        for e: int in rep$elements(s) do
            yield (e)
        end
    end elements

end intset

Code outside the cluster can only call intset$create, intset$insert, intset$member and intset$elements. It cannot tell that an intset is an array, so the representation can be changed without changing any code that uses it.

Explicit operation names and syntactic sugar

Every operation belongs to a type and is named type$operation, for example intset$insert(s, 3). This removes any need for overloading. Operators are shorthand: x + y is rewritten by the compiler as t$add(x, y), where t is the type of x. The same rule applies to built-in and user-defined types, so a user-defined type gets + just by naming an operation add. Liskov reported that, to her surprise, users liked the t$o notation because they believed it improved program correctness and readability.

Iterators

Iterators are CLU’s best-known contribution. An iterator is a routine that yields values one at a time to a for loop:

evens = iter (lo, hi: int) yields (int)
    i: int := lo
    if int$mod(i, 2) ~= 0 then i := i + 1 end
    while i <= hi do
        yield (i)
        i := i + 2
    end
end evens

% usage:
%   for n: int in evens(1, 10) do ... end

The idea came from generators in Alphard, the data-abstraction language being developed at Carnegie Mellon. The CLU group saw them on a visit to CMU in summer 1975 and thought they were too complicated. Russ Atkinson designed CLU’s iterators on the flight back to Boston and wrote them up in a design note in September 1975. CLU iterators were deliberately restricted, so that they can be nested but not run side by side. In return they can be implemented on a single stack: each yield is effectively a call to the body of the loop.

Exceptions

A CLU procedure declares the exceptions it can raise as part of its signature, raises them with signal, and callers handle them with except when:

pop = proc (s: stack) returns (int) signals (empty)
    ...
end pop

n: int
n := int$parse(text)
   except when bad_format, overflow: n := 0
   end

CLU uses the termination model: a procedure either returns normally or ends in one of its named exceptions. The designers rejected the resumption model of PL/I and Mesa as too complex. CLU also does not propagate exceptions automatically. An exception that the caller does not handle becomes the special exception failure, so a procedure can never raise an exception that is not in its specification. The main principles were settled by June 1975 and the design was complete by fall 1977. Because exceptions were implemented cheaply, CLU programmers used them as an ordinary way to return information to the caller, not only for errors.

Parameterized types

Built-in types such as array are type generators: array[int] and array[string] are different types. Users can write their own generators, and a where clause states what operations a type parameter must provide:

set = cluster [t: type] is create, member, size, insert, delete, elements
    where t has equal: proctype (t, t) returns (bool)

The compiler checks each instantiation against the where clause, so parameterized code is fully type-checked. In CLU .5, parameterized types were still checked at run time; the where clause came later. Liskov wrote in 1992 that CLU “was way ahead of its time” here, since most languages still lacked parametric polymorphism.

Other features

  • Multiple assignment and multiple return values: x, y := y, x, and q, r := divide(a, b).
  • Mutable and immutable type pairs: array/sequence, record/struct, and variant/oneof. The last two are tagged unions.
  • First-class procedures that can be passed, returned and stored. They cannot have free variables, so CLU has no closures. Liskov counted closures and recursive type definitions as the main missing features.
  • Type any, the union of all types, with a checked run-time force to recover the real type.
  • A program library of interface descriptions, so modules could be type-checked against the interfaces of modules not yet written.

Evolution

Once the design was frozen in 1979, CLU changed very little. Work moved to implementations and to successor languages:

ImplementationTargetNotes
CLU .5 compiler (from 1974)PDP-10Generated Lisp, then MDL; later rewritten to generate macro-assembler
Production compiler (1980)DECSYSTEM-20Machine code, static instantiation of generics, intermodule type checking
Native CLUVAX, then 68000Retargets of the production compiler; the 68000 port was by Sharon Perl
Portable CLU (PCLU)Unix via CCompiles CLU to C. Release 3.6 is dated 17 March 1992; Release 3.7 (30 November 2016) runs on 64-bit Linux

Dorothy Curtis did the Portable CLU work. The 3.7 README says plainly that “CLU is no longer actively maintained” and that the release updated 3.6 for 64-bit Linux, tested on Debian 8.6. Enthusiasts have since patched PCLU further. One fork (nbuwe/pclu, mirrored on GitHub) describes itself as “Portable CLU fixed to actually work,” and a separate clu2c translator exists as well.

The closest successor is Argus, which Liskov’s group developed next. It adds guardians and atomic transactions for distributed programs, and some features CLU lacked. At Cambridge, CCLU extended CLU for concurrent systems programming.

Current Relevance

CLU itself is a historical language. Nobody develops it, and in practice the way to run it today is Portable CLU on Unix-like systems (or one of the community-patched forks) or the archived PDP-10 files. There is no Docker image. In 2021 MIT’s Department of Distinctive Collections published CLU files from 1976 to 1989, recovered from the Tapes of Tech Square backup tapes. The collection includes the 1977-78 CLUSYS runtime and version 3.x compilers from 1978.

The ideas are still widely used. Liskov’s 1987 OOPSLA keynote “Data Abstraction and Hierarchy” came out of the same line of work and is the source of the Liskov substitution principle. In 2009 she received the 2008 ACM A.M. Turing Award for contributions to programming language and system design, particularly data abstraction, fault tolerance and distributed computing.

Why It Matters

Liskov’s 1992 history names Ada, C++, ML, Modula-3 and Trellis/Owl as languages influenced by CLU. Other designers have said the same about their own languages:

  • C++: Bjarne Stroustrup’s history of C++ says “the main sources for ideas for C++ were Simula, Algol68, and later Clu, Ada, and ML”. His 1986 paper “What is Object-Oriented Programming?”, quoted there, lists “Ada, Clu, and ML” as supporting parameterized types that C++ then lacked, and “Ada, Algol68, and Clu” as having standard exception handling.
  • Lua: The Lua designers’ HOPL III paper states: “From CLU we took multiple assignment and multiple returns from function calls.”
  • Sather and Python: Python’s PEP 255, which added generators, points to “iterators in Sather, which were inspired by iterators in CLU.”
  • Ruby: Yukihiro Matsumoto has said Ruby’s blocks came from CLU’s iterators, according to a 2019 AppFolio Engineering account of Ruby’s roots.
  • Swift: Chris Lattner’s 2014 homepage note lists CLU among the languages whose experience Swift drew on.

CLU had these ideas decades before most of the languages that use them today: encapsulation enforced by the compiler, generic code checked without access to its implementation, exceptions as part of a procedure’s contract, and iteration that separates producing values from using them. Its designers set out to influence other languages rather than to be widely used, and that is what happened.

Timeline

1973
Liskov and Stephen Zilles work out language support for abstract types over the spring and summer. In the fall, the name CLU (the first three letters of "cluster") is chosen and design work starts in earnest. The first internal design note is dated 6 December 1973
1974
Liskov and Zilles present "Programming with Abstract Data Types" at the ACM SIGPLAN Symposium on Very High Level Languages in April. Work on a compiler for the preliminary CLU .5 starts that summer on the PDP-10
1975
The preliminary CLU .5 reference manual is issued internally in January. The main principles of the exception mechanism are settled by June, and Russ Atkinson describes iterators in a design note in September
1977
"Abstraction Mechanisms in CLU" by Liskov, Snyder, Atkinson and Schaffert appears in Communications of the ACM in August. The compiler is reimplemented to generate macro-assembler instead of MDL
1978
The CLU Reference Manual is published as an MIT technical report in July
1979
A final design pass adds the resignal statement and own data. The 78th and last design note appears on 30 July, and the final reference manual is published in October
1980
A production-quality compiler generating machine code for the DECSYSTEM-20 is ready to be exported to other groups
1981
Springer-Verlag publishes the CLU Reference Manual as Lecture Notes in Computer Science volume 114
1992
Portable CLU Release 3.6, which compiles CLU to C, is dated 17 March. In April, Liskov completes "A History of CLU" for the second History of Programming Languages conference (HOPL-II)
2009
Liskov receives the 2008 ACM A.M. Turing Award, announced in March 2009, with data abstraction among the contributions cited
2016
Portable CLU Release 3.7, dated 30 November, updates PCLU to run on 64-bit Linux
2021
MIT Libraries publish CLU files from 1976 to 1989, recovered from the Tapes of Tech Square collection, on GitHub under the MIT No Attribution licence

Notable Uses & Legacy

The CLU compiler

The first compiler was written in Lisp but soon rewritten in CLU itself. Liskov wrote that using CLU to implement its own compiler was very helpful in evaluating the language's expressive power

LP, the Larch Prover

The LP theorem-proving system and related work on rewriting systems were written in CLU. Liskov's 1992 history says CLU was still being used for LP at that time

MIT teaching

CLU was used in MIT's software engineering and compiler construction courses, and it is the language of Liskov and Guttag's textbook Abstraction and Specification in Program Development (1986)

Tokyo Institute of Technology

According to Liskov's 1992 history, CLU was "the language" of the Information Science department at the Tokyo Institute of Technology

Argus and CCLU

Liskov's distributed-programming language Argus was built on CLU. At Cambridge University, CCLU, a concurrent CLU that grew out of MIT's Swift project, was used for systems research

MIT editors and design tools

Liskov lists a text editor called TED, a WYSIWYG editor called ETUDE, a database schema browser, a circuit design system and a gate-array layout system among the applications written in CLU

Language Influence

Influenced By

Lisp ALGOL 60 Simula Alphard

Influenced

Argus C++ Ada Modula-3 Lua Sather Ruby Swift

Running Today

Run examples using the official Docker image:

docker pull
Last updated: