The language you never used, running everywhere
There is a good chance you have never written a line of Strongtalk. There is a near certainty you ran its ideas today.
Strongtalk was a Smalltalk with optional static types, built by a seven-person startup in Palo Alto between 1994 and 1996. It never shipped as a product. Sun Microsystems bought the company in February 1997, and the team turned its virtual machine into Java HotSpot.
The same handful of people went on to build Google’s V8 JavaScript engine, co-design Go and Dart, and run Google’s infrastructure. The idea at the heart of its type system — types you can add or leave out, which never change how a program runs — is the bargain TypeScript and Python type hints offer millions of developers today.
This is the story of where Strongtalk came from, what it got right, and where its ideas went. It ends with a small revival: I rebuilt Strongtalk in Rust, made it run in the browser, and taught it to translate itself into TypeScript.
Roots I: Smalltalk-80 and the first fast Smalltalk
Smalltalk came out of Xerox PARC in the 1970s, and Smalltalk-80 was the version the wider world met. Its premise was radical and simple: everything is an object, and everything happens by sending messages. 3 + 4 is the message + sent to the object 3.
That purity had a price. Every operation, even integer addition, was a dynamic message send, looked up at run time. Early Smalltalk systems were interpreters, and they were slow.
In January 1984, L. Peter Deutsch and Allan Schiffman published “Efficient implementation of the Smalltalk-80 system” at POPL. Two of its ideas still sit inside every fast dynamic-language runtime:
Dynamic translation. Compile methods to machine code on first use and cache the result: what we now call a just-in-time compiler.
Inline caching. At each call site, remember the class of the last receiver and where its method lives. Next time, check the class and jump straight there, skipping the lookup.
Inline caches work because most call sites are boring: the same kind of object arrives again and again. Strongtalk’s story is, in a sense, the story of taking that observation as far as it can go.
Roots II: Self, the language that was faster than it had any right to be
In 1986 at Xerox PARC, David Ungar and Randall Smith designed Self, a language even more dynamic than Smalltalk. It dropped classes entirely: objects are made by copying other objects, and they inherit through prototype links. They moved to Stanford, built the first Self compiler in 1987, released it publicly in 1990, and took the project to Sun Microsystems in 1991.
Self should have been hopelessly slow. Instead, its research group produced a run of implementation ideas that still define how dynamic languages are made fast:
Maps (1989). Objects with the same layout share a hidden description of that layout. Today JavaScript engines call these hidden classes.
Customized compilation. Compile a separate version of a method for each kind of receiver, so inside that version the receiver’s type is known.
Polymorphic inline caches (1991). Urs Hölzle, Craig Chambers and David Ungar extended Deutsch and Schiffman’s one-entry cache to hold several receiver types per call site (ECOOP ‘91).
Type feedback and adaptive optimization (1994). Those caches quietly record which types actually reach each call site. Hölzle’s Stanford thesis used that record to find the hot spots of a running program and recompile them with the common cases inlined. Large Self programs ran 1.7 times faster than without it.
Note the word hot spots. Lars Bak, then a young Danish engineer in the Self group at Sun Labs, worked on the Self virtual machine. In 1994, Hölzle, freshly done with his thesis, and Bak took these ideas out of the lab.
Roots III: a type system that would not get in the way
The third root came from a frustrated user. Dave Griswold wanted to use Smalltalk for real production software. In his own account, three things stood in the way: Smalltalk was “way too slow for any kind of compute intensive application”, it had no type system, and it had poor support for native user interfaces.
For the types, Griswold hired Gilad Bracha, whose 1991 PhD at the University of Utah had been on mixins and modularity. Together they built a static type checker for Smalltalk and described it at OOPSLA 1993 in “Strongtalk: Typechecking Smalltalk in a Production Environment”.
That first system sat on top of the commercial ParcPlace Smalltalk, and Griswold later called it “pretty ungainly”. The reason is instructive. Smalltalk’s class library reuses code wherever it is convenient: Dictionary inherits from Set, although a dictionary is not a set you can use in place of one. A type checker has to know which classes are true subtypes, so the typed system "had to use a declared hierarchy that differed from actual underlying hierarchy".
The lesson was that types work best when the library is designed with them. To do that properly, the team needed their own Smalltalk, from the virtual machine up.
Animorphic Systems: seven people and a clean slate
In the fall of 1994, Griswold, Hölzle, Bak and others formed LongView Technologies LLC, which did business in Palo Alto as Animorphic Systems. Griswold’s history of the project lists the whole team, alphabetically:
Person
What they built
Lars Bak
the virtual machine (“the VM wizard”)
Gilad Bracha
the type checker, the reflective interface, mixins at the Smalltalk level
Steffen Grarup
the garbage collector, the programming environment, the source code manager
Robert Griesemer
the interpreter, the interpreter generator, most of the compiler
David Griswold
the typed class libraries, the user interface framework, an HTML browser; managed the group
Urs Hölzle
the compiler and its inlining infrastructure
Srdjan Mitrovic
joined later and adapted the technology to Java
They had a rare advantage: the research was already done. Self had shown how to make a dynamic language fast; the 1993 checker had shown how to type Smalltalk. Animorphic’s job was to build both properly, together, in one production system.
By 1996, Griswold wrote, “the system was working nicely”. They showed it at an OOPSLA booth late that year, and a few people evaluated it privately. Then, in Griswold’s words, “the Java phenomenon happened”.
The type system: optional, and never in charge
Strongtalk’s central design decision was a separation. In Griswold’s words, the type system and the virtual machine “were independent of each other. This independence was critical, since the system would need to accept untyped as well as typed code, so that people could use the type system as much or as little as they wanted to, without impacting performance.”
Types are written in angle brackets after the name they describe. Here are three methods from Sun’s own Collection.dlt, the root of the collection library:
collect: map <[E, ^R def]> ^<Cltn[R]> ^self collectUsingAdd: mapdetect: predicate <[E, ^Boolean]> ifNone: fail <[^X def]> ^<E|X> self do: [:e <E> | (predicate value: e) ifTrue: [^e]]. ^fail valueinject: val <X> into: f <[X def, E, ^X]> ^<X> | v <X> | v := val. self do: [:e <E> | v := f value: v value: e]. ^vRead them slowly, because they were ahead of their time:
Block types.
<[E, ^Boolean]>is a function from an element to a Boolean. Smalltalk is built on blocks, so the type system had to describe them.Generics with declared variance.
Collectionis defined withGeneric forAll: '(E covar)': a collection of integers may be used where a collection of numbers is expected.Type inference at the call.
R defandX defdeclare type variables that are worked out from the arguments at each call, socollect:on a collection of strings returns a collection of whatever the block answers.Union types.
detect:ifNone:answers either an element or whatever the fallback block answers:<E|X>.Self types. A method declared
^<Self>keeps returning the right type in every subclass.
Two deeper choices shaped everything else. Types were protocols, not classes: a type describes the messages an object understands, so subtyping is separated from the inheritance that shares code. That fixes the Dictionary/Set problem from the first version. And the library was built from mixins: Sun's OrderedCollection is literally defined as VarSequenceableCollection[E] mixin |> AddableSequenceableCollection[E].
Finally, the type checker never decided how code ran. Delete every annotation and the program behaves exactly the same; untyped code is simply trusted. When you know better than the checker, guaranteed <Int> expr tells it so. If that bargain sounds familiar, it should: it is the one TypeScript offers today.
The virtual machine: betting on what the program actually does
Here is the twist most people miss: Strongtalk’s speed had nothing to do with its types. Griswold is explicit that the type system “was not used for optimization”. The VM treated typed and untyped code the same, and learned what it needed by watching the program run.
The pieces were the Self lineage, rebuilt for production:
- 1.
A fast interpreter, generated rather than hand-written. Robert Griesemer wrote an interpreter generator, so the interpreter’s machine code came out of a description of the bytecodes.
- 2.
Tagged integers. Small integers lived directly in the pointer word, 30 bits of value with a tag in the low bits, so
3 + 4allocated nothing. - 3.
Inline caches as a profiler. Every send site’s cache recorded which classes really arrived there.
- 4.
A type-feedback compiler. Hölzle’s compiler used those records to inline the common case, guarded by a cheap class check.
- 5.
Deoptimization. When a guess turned out wrong, the system could, in Griswold’s words, “deoptimize and back out on-the-fly” to slower, general code.
The payoff was large. Static techniques alone could inline “about 25% of sends”; type feedback inlined “the vast majority of message sends in general purpose code”. Griswold recalls one early user getting “a speedup of 12 on some real Smalltalk code”. The trade report on the acquisition quoted claims of 3.5 times the speed of other Smalltalk VMs, and twice the speed of other Java VMs.
That last number is the important one. By early 1997 the same engine was running Java.
Sun buys Animorphic: a Smalltalk VM becomes Java HotSpot
In the mid-1990s Java was everywhere and slow. Its first virtual machines interpreted bytecode, and a dynamic, object-oriented language with virtual calls everywhere posed exactly the problem Self and Strongtalk had solved.
On 19 February 1997, Tech Monitor reported that Sun’s JavaSoft had bought LongView Technologies “for an undisclosed cash sum”, and that “the seven-person Animorphic team has joined JavaSoft already”. The headline said it all: JavaSoft picks Animorphic’s HotSpot VM. The name was already there. It describes what the VM does: find a program’s hot spots while it runs, and optimize them.
The Java HotSpot Performance Engine shipped on 27 April 1999, first as an add-on for Java 1.2. It became the default Sun JVM in Java 1.3 and has been the reference Java virtual machine ever since. Lars Bak became engineering manager and technical lead of the HotSpot team.
Strongtalk itself was the casualty. As Griswold put it, they “eventually had to switch to Java before ever releasing it”, and the system “disappeared from view”. A finished, fast, typed Smalltalk went into a drawer at Sun, while its engine went on to run a large share of the world’s server software.
The diaspora: where the people went, and what they carried
Companies end; teams scatter; ideas travel in people’s heads. Follow four of the seven and you trace much of the modern runtime landscape.
[embed: node/9c1310f6-c528]
Strongtalk joined Self’s implementation ideas to a typed Smalltalk; the people who built it carried both into the systems on the right.
Urs Hölzle joined Google in 1999 as its eighth employee and became its first VP of Engineering later that year. He went on to lead Google’s technical infrastructure as a Senior Vice President until 2023. The engineer who taught Self to find its hot spots ended up responsible for some of the largest computers ever built.
Lars Bak returned to Aarhus, Denmark, founded the mobile VM company OOVM in 2002, and joined Google in 2006 to build a JavaScript engine for Chrome. V8 shipped on 2 September 2008, built by a team of about twelve. Its lineage is written into the code: Wikipedia notes that V8 is “strongly inspired by the Java HotSpot Virtual Machine” and that its assembler “is based on the Strongtalk assembler”. Self’s maps returned as V8’s hidden classes; inline caches came along too.
In October 2011, Bak and Kasper Lund unveiled Dart at the GOTO conference in Aarhus. Dart 1 had optional types; Dart 2 made the type system sound in 2018. Dart now powers Flutter. In 2017, Bak and Lund left Google to found Toit, a language for small devices.
Robert Griesemer, who wrote Strongtalk’s interpreter and most of its compiler, designed Go with Rob Pike and Ken Thompson, starting in 2007. Go was announced in November 2009.
Gilad Bracha co-authored the second and third editions of the Java Language Specification, worked on Dart at Google, and created Newspeak, a descendant of Smalltalk. He has argued for pluggable type systems: optional checkers that never affect run-time semantics, which is Strongtalk’s founding principle given a name.
The ideas, everywhere now
Strongtalk lost as a product and won as a set of ideas. Two of them are now so normal that we forget anyone had to invent them.
Adaptive optimization is how dynamic code runs. Watch the program, bet on what usually happens, inline it, and back out safely when the bet fails. That is the recipe inside HotSpot, inside V8, and in some form inside every serious JavaScript engine. Inline caches and hidden classes are standard vocabulary for anyone who works on them.
Optional types that never change behaviour are how dynamic languages got types. Strongtalk’s rule was that you could delete every annotation and the program would run the same. Compare the design documents of today’s most used typed-on-top languages:
Types optional?
Change run-time behaviour?
Structural?
Strongtalk (1993–1996)
yes
no: “independent” of the VM
yes: types are protocols
yes
no: “Preserve runtime behavior of all JavaScript code”
yes: “fully erasable, structural”
yes: “no desire to ever make type hints mandatory”
no: “no type checking happens at runtime”
partly: nominal classes plus structural protocols
Dart 1 (2011)
yes
no in production mode; enforced in “checked mode”
no
I am not claiming TypeScript or Python copied Strongtalk; good ideas get found more than once. But Strongtalk was there first in a production-quality system, and it made the argument that convinced a generation: you can have dynamic freedom and static checking in the same program, and the checking should serve the programmer rather than rule the runtime.
The one place they part ways is soundness. Strongtalk set out to offer “stronger type safety guarantees” than an unchecked Smalltalk; TypeScript explicitly chose not to be sound, aiming to “strike a balance between correctness and productivity”. Dart started optional and moved to a sound type system with Dart 2 in 2018.
Open source, and a revival in Rust
Strongtalk did come out of the drawer, slowly. Sun released the system image in 2002 and the virtual machine source in 2006, under a BSD license; Griswold thanked Gilad Bracha “for persevering and making this happen”. Griswold’s closing words on the project’s site are a challenge: “Strongtalk contains innovations that are still far ahead of virtually any existing mainstream language or VM. Now that Strongtalk is open source, the future is up to you!”
The catch was that the 2006 VM was a 32-bit Windows program, written for the machines of 1996. Today it is hard to run at all.
So I rebuilt it. Strongtalk, the Rust edition re-implements the language from the original system:
A Rust virtual machine with a parser for the full typed syntax, a bytecode compiler, the whole numeric tower (
100 factorialjust works), blocks with non-local return, ANSI exceptions, and a type checker.The browser environment. Compiled to WebAssembly, it runs the classic Strongtalk desktop in a browser tab: workspaces, class browsers, inspectors and the type checker, with nothing to install.
A Strongtalk-to-TypeScript translator. Since Strongtalk and TypeScript share the same bargain, a typed Smalltalk program maps onto readable TypeScript:
<Int>becomesnumber,<Self>becomesthis,to:do:becomes aforloop, and a^inside a block still returns from its method. A test suite runs each program in both and checks that they print the same.Installers for macOS, Windows and Linux, and the original BSD license, with Sun’s notice kept.
You can try it now at strongtalk-rs.org, or read the source on GitHub. The translator page runs your Strongtalk in the VM and its TypeScript translation side by side.
(1 to: 10) collect: [:i <Int> | i * i]becomes
$range(1, 10).map((i: number) => i * i)What Strongtalk teaches
Strongtalk is a reminder that the unit of progress in computing is often not the product but the idea, and the people who carry it.
It was never released as a product. Outside the team, it was seen at one conference booth and by a few private evaluators. Yet its virtual machine became Java’s, its engineers built the engine inside Chrome and Node.js, and its central argument about types is now the default way the most popular dynamic languages are typed.
Three lessons seem worth keeping:
- 1.
Keep the type system out of the runtime’s way. Strongtalk’s types could be added gradually because they never changed what a program did. TypeScript and Python’s type hints make the same promise today.
- 2.
Measure, then bet. The fastest dynamic code comes from watching what a program actually does and optimizing for that, with a safe way back when the bet is wrong.
- 3.
Small teams with finished research move fast. Seven people built a production Smalltalk, a type system and a world-class VM in about two years, because Self and the 1993 checker had already done the hard thinking.
The next time a JavaScript engine inlines your method call, or TypeScript accepts your untyped code without complaint, you are using something a small company in Palo Alto worked out in 1996.