Est. 1995 Intermediate

Limbo

Bell Labs' concurrent systems language for the Inferno operating system - a C-flavored, garbage-collected language with typed channels, abstract data types, and dynamically loaded modules, compiled to the portable Dis virtual machine, that later fed directly into the design of Go

Created by Sean Dorward, Phil Winterbottom, and Rob Pike at Bell Labs (Computing Sciences Research Center); Dennis Ritchie wrote the language description

Paradigm Multi-paradigm: Procedural, Concurrent (CSP-style channels), Modular
Typing Static, Strong (compile-time checks with run-time type safety enforced by the Dis virtual machine)
First Appeared 1995 (development began; publicly presented with Inferno in 1996)
Latest Version Inferno 4th Edition (public release 2004-2005; relicensed under the MIT License in March 2021; the community Inferno64 fork, active since approximately 2022, extends Dis to 64 bits)

Limbo is the application programming language of Inferno, the distributed operating system that Bell Labs built in the mid-1990s as a successor-in-spirit to Plan 9. Designed by Sean Dorward, Phil Winterbottom, and Rob Pike, and described in a language report written by Dennis Ritchie, Limbo is a compact, C-like language with garbage collection, strong static typing, abstract data types, first-class communication channels, and cheap lightweight processes. Limbo programs compile to bytecode for the Dis virtual machine, which lets the same binary run on any Inferno host or native port. It never became a mainstream language, but its concurrency model - spawn, typed chans, and alt - was carried almost intact into Go, which makes Limbo one of the more consequential “dormant” languages in the systems world.

History & Origins

Bell Labs after Plan 9

By 1995 the Computing Sciences Research Center at Bell Labs had spent nearly a decade on Plan 9, the research operating system that generalized the Unix “everything is a file” idea into a network protocol (9P) and a per-process namespace. Plan 9’s application language was Alef, a C-like language by Phil Winterbottom that added abstract data types and CSP-style channels. Alef was compiled to native code and had to be ported, compiler and all, to every architecture Plan 9 supported.

The Inferno project began in 1995 with a different target: small, networked consumer devices - set-top boxes, “intelligent” telephones, PDAs - with limited memory and no fixed architecture. The team (Dorward, Winterbottom, and Pike, with Dave Presotto, Howard Trickey, and Dennis Ritchie also on the Inferno papers) wanted the Plan 9 model of files and namespaces, but with a language that was safe, garbage collected, and portable across hardware without recompilation. Limbo was the answer. Its name, like Inferno’s, comes from Dante; the virtual machine is Dis, the city of the lower Inferno, and the file protocol is Styx.

Java’s competitor

Dennis Ritchie reportedly let the existence of the project slip in early 1996, after less than a year of development, and Lucent Technologies - freshly spun out of AT&T - presented Inferno publicly later that year as a direct competitor to Java for networked devices. The comparison was apt: both were garbage-collected, virtual-machine-based, and aimed at portable code for a networked world. Inferno 1.0 shipped in 1997, and Lucent set up a dedicated Inferno Business Unit to sell it.

The commercial push did not last. Lucent used Inferno in two of its own products - the PathStar access server and the VPN Firewall Brick - but the business unit closed in 2000, and in March of that year Lucent sold the rights to Vita Nuova Holdings, a small company in York, England, with close ties to the Plan 9 and Inferno research community. Vita Nuova released the 3rd Edition in 2001 and, beginning with a preliminary public release in May 2004, moved the 4th Edition to free-software terms. In March 2021 all editions were relicensed under the MIT License, and community forks such as Inferno64 have since carried the system to 64-bit hosts.

Design Philosophy

Ritchie’s language report summarizes Limbo’s ancestry in one sentence: expression syntax and control flow from C, declarations from Pascal, abstract data types and channels from Alef, and processes from Hoare’s CSP and Pike’s Newsqueak. Around that core, several principles shaped the language:

  • Safety without a native compiler. Limbo has no pointer arithmetic, no unchecked casts, and no unsafe memory access. Type safety is verified at compile time and enforced at run time by the Dis VM, which lets untrusted Limbo modules be loaded into a running system.
  • Portability as a first-class goal. Limbo compiles to Dis bytecode, not machine code. The Dis instruction set was designed to be translated to native code cheaply at load time, so a single .dis file runs on any architecture with a Dis port - x86, ARM, MIPS, and PowerPC among others, according to the Inferno documentation.
  • Concurrency as a language feature. Processes are created with spawn, communicate over typed channels, and multiplex with alt. Shared memory is possible but the idiom is message passing.
  • Modules as the unit of everything. Programs are collections of modules with explicit interfaces. Modules are loaded dynamically by path name, so the file system - and therefore the network, via Styx - is the module namespace.
  • Small enough for appliances. The whole runtime, including the VM, garbage collector, and graphics, was meant to fit in a device with roughly a megabyte of memory, according to the original Inferno papers.

Key Features

Types and declarations

Limbo’s basic types are byte, int (32-bit), big (64-bit), real (64-bit floating point), and string. Compound types include fixed-size array of T, singly linked list of T, tuples such as (int, string), chan of T, ref to an adt, and function types. Declarations follow the Pascal convention of name first:

count: int;
names: list of string;
grid := array[10] of { * => 0 };   # := declares and initializes
pair := (3, "three");

Strings are immutable Unicode sequences with built-in concatenation and slicing; arrays and lists are garbage collected, as are adt instances allocated with ref.

Abstract data types

An adt groups data members with the functions that operate on them, giving encapsulation without inheritance:

Point: adt {
    x, y: int;
    add: fn(p: self Point, q: Point): Point;
    eq:  fn(p: self Point, q: Point): int;
};

Point.add(p: self Point, q: Point): Point
{
    return (p.x + q.x, p.y + q.y);
}

A pick adt is a tagged union - a discriminated variant whose branches are checked by a pick statement, roughly comparable to a sum type in ML-family languages.

Modules

Every Limbo program is a module with a declared interface. The famous minimal program shows the shape:

implement Hello;

include "sys.m";
include "draw.m";

sys: Sys;

Hello: module
{
    init: fn(ctxt: ref Draw->Context, argv: list of string);
};

init(nil: ref Draw->Context, nil: list of string)
{
    sys = load Sys Sys->PATH;
    sys->print("Hello, World!\n");
}

include pulls in the interface declaration for the system module; load fetches the implementation from the file system at run time (Sys->PATH is the $Sys built-in, but application modules are loaded from ordinary .dis files by path). Because loading happens through the namespace, a module can just as easily come from a remote Styx server as from local storage.

Channels, spawn, and alt

The concurrency primitives are what most people remember Limbo for. spawn starts a new Dis process running a function call; chan of T declares a typed channel; <- sends and receives; and alt waits on several channels at once:

c := chan of int;
done := chan of string;

spawn producer(c);

alt {
    n := <-c =>
        sys->print("got %d\n", n);
    s := <-done =>
        sys->print("finished: %s\n", s);
}

Channels can be buffered (chan[8] of int), sent over other channels, and even exported to the file system so that other machines can talk to a Limbo process over Styx. Dis processes are designed to be far cheaper than host threads (they are scheduled by the VM rather than the host OS), so Limbo programs routinely use many of them - the same style Go later called goroutines.

Exceptions and the runtime

Limbo has an exception mechanism (raise and exception blocks), reportedly added in later editions, module-level garbage collection using a hybrid of reference counting and a real-time collector for cyclic data, and a built-in Sys module that exposes the Inferno system calls - file operations, bind and mount for namespace manipulation, and Styx - directly to programs. Graphics come through the Draw and Tk modules; the window manager, editors, and browser in Inferno are all Limbo programs using them.

Evolution

PeriodStewardDevelopment
1995-1997Bell Labs / LucentLanguage designed; Inferno 1.0 and the Ritchie language report
1997-2000Lucent Inferno Business Unit2nd Edition (1999); commercial licensing; PathStar and Firewall Brick
2000-2004Vita Nuova (proprietary)3rd Edition (2001); commercial and subscription licensing
2004-2021Vita Nuova (open source)4th Edition with 9P2000 support; mixed GPL/LGPL/LPL/MIT licensing; Ritchie’s language report revised for the 4th Edition
2021-presentCommunityMIT relicensing (March 2021); Inferno64 fork (2022); ports to Raspberry Pi, Android, and other hosts

The language itself changed little across editions. The most visible additions were exception handling, the pick adt, and refinements to the module system; the 4th Edition’s interface changes were mostly in the system modules rather than the language. Most of the activity in the last two decades has been in keeping the hosted emulator building on modern operating systems and widening the Dis VM to 64 bits.

Current Relevance

Limbo is dormant rather than dead. The Inferno source tree, including the limbo compiler and the emu hosted environment, is maintained on GitHub under the MIT License and is reported to build on Linux, macOS, FreeBSD, and other hosts; the repository ships a Dockerfile that builds a 32-bit hosted Inferno and launches its window manager. Forks such as Inferno64 and 9ferno keep it running on current 64-bit machines, and hobbyists have carried it to Raspberry Pi boards and Android phones (the Sandia Hellaphone project), with ports to other targets such as RISC-V reportedly in progress.

There is no significant commercial use today and no active language evolution. What remains is a small community of Plan 9 and Inferno enthusiasts, a complete and readable reference implementation, and a body of documentation - Ritchie’s language report, Brian Kernighan’s “A Descent into Limbo” tutorial, and Phillip Stanley-Marbell’s book Inferno Programming with Limbo (2003) - that makes the language unusually easy to learn for something so obscure.

Why It Matters

Limbo’s importance is mostly measured through Go. When Rob Pike, Ken Thompson, and Robert Griesemer began designing Go at Google in 2007, they brought the Bell Labs lineage with them, and Go’s FAQ states that its concurrency model descends from the CSP-inspired family that includes Newsqueak and Limbo. Go’s chan, select, and go statement are the direct heirs of Limbo’s chan, alt, and spawn; Go’s name-first declaration syntax, its := short declaration, and its packages-as-modules model all have visible Limbo ancestors. Anyone who has written a Go program has, in effect, written a Limbo program with the semicolons removed.

Beyond Go, Limbo was an early and thorough demonstration of the “safe language on a portable VM” approach to embedded and networked software - the same bet Java made, tried at the same time with a much smaller runtime and a more radical operating-system model. It showed that CSP-style concurrency could be made pleasant in a C-shaped language, that dynamically loaded modules could be typed and safe, and that a file-system namespace could serve as the loader, the RPC mechanism, and the security boundary all at once. Inferno lost the commercial contest with Java in the 1990s, but the ideas that Limbo carried are now in one of the most widely used languages in the world.

Timeline

1995
Work on Inferno and its application language Limbo begins at Bell Labs' Computing Sciences Research Center, led by Sean Dorward, Phil Winterbottom, and Rob Pike, building on Plan 9 ideas and on Winterbottom's Alef and Pike's Newsqueak
1996
Dennis Ritchie reportedly lets slip the existence of Inferno early in the year; Lucent Technologies (spun off from AT&T) presents Inferno and Limbo publicly later in 1996, positioning them against Java for networked consumer devices and set-top boxes
1997
Inferno 1.0 ships from Lucent in the spring; the Bell Labs Technical Journal paper 'The Inferno Operating System' by Dorward, Pike, Presotto, Ritchie, Trickey, and Winterbottom describes the system, and Ritchie's 'The Limbo Programming Language' appears in the Inferno Programmer's Manual
1999
Inferno 2nd Edition released (reportedly in July) by Lucent's Inferno Business Unit
2000
Lucent winds down the Inferno Business Unit and in March sells the rights to Inferno and Limbo to Vita Nuova Holdings of York, England, a small company with close ties to the Plan 9 and Inferno research community
2001
Vita Nuova releases Inferno 3rd Edition (reportedly in June)
2004
A preliminary public release of Inferno 4th Edition appears in May; the 4th Edition adds 9P2000 support, and Vita Nuova moves the system to free-software terms (a mix of GPL, LGPL, Lucent Public License, and MIT for different parts) with the full release generally dated to early 2005
2009
Google releases Go, whose FAQ names Newsqueak and Limbo among the CSP-inspired languages from which its channel-based concurrency model descends
2011
The Hellaphone project at Sandia National Laboratories puts hosted Inferno on Android phones, replacing the Java layer with a Limbo user environment; it is presented at DEF CON 20 in 2012
2021
In March, all editions of Inferno (and with them the Limbo compiler and libraries) are relicensed under the MIT License
2022
The community Inferno64 fork, active around this time, extends the Dis virtual machine and Limbo toolchain to 64-bit hosts

Notable Uses & Legacy

Inferno operating system

Every user-level program in Inferno - the shell, the window manager, the Acme editor port, the Charon web browser, and the utilities - is written in Limbo and runs as Dis bytecode on the Inferno kernel or the hosted emu

Lucent PathStar access server

Lucent's PathStar combined voice/data switch used Inferno internally, with control software reportedly written in Limbo - one of the two Lucent products commonly cited as shipping on the system

Lucent VPN Firewall Brick

Lucent's network security appliance was the other internal Lucent product built on Inferno and Limbo

Hellaphone (Sandia National Laboratories)

Ran Inferno on top of Android's Linux kernel with the Java stack disabled, providing a phone dialer, SMS, editors, shell, compiler, web browser, mail client, and games written in Limbo, reportedly in well under a million lines of code

Vita Nuova grid and embedded products

Vita Nuova used Inferno and Limbo for grid-computing tools and embedded deployments across Windows, Linux, and Unix hosts and small ARM, MIPS, PowerPC, and x86 devices

Language Influence

Influenced By

C Pascal Alef Newsqueak CSP

Influenced

Running Today

Run examples using the official Docker image:

docker pull
Last updated: