Introduction
“The limits of my language mean the limits of my world.”
— Ludwig Wittgenstein
Every programming language embodies a philosophy—a set of beliefs about how programs should be structured, how complexity should be managed, and what concepts are fundamental versus incidental. Java believes in protective encapsulation and type safety. Lisp believes in code as data. Haskell believes in mathematical purity.
Io believes in radical simplicity through uniform message passing.
The Birth of Io #
Steve Dekorte created Io in 2002, during an interesting period in programming language history. Java had conquered the enterprise. Python and Ruby were gaining traction as “scripting” languages. JavaScript was still dismissed as a toy for web browsers. The mainstream programming world had largely settled on class-based object-orientation as the “right” way to organize programs.
But Dekorte was inspired by older, more radical ideas:
- Smalltalk (1972): Everything is an object, computation happens through message passing
- Self (1986): Objects without classes, prototype-based inheritance
- Lisp (1958): Code as data, minimal syntax, powerful macros
- Lua (1993): Simplicity, embeddability, tables as the universal data structure
- NewtonScript (1993): Prototype-based inheritance in a practical system
Here’s how Dekorte himself described his motivation:
“I wanted a language that was small, simple, and consistent. Something you could understand completely. Most languages accumulate features over time, becoming more complex. I wanted to go the opposite direction—to see how much you could accomplish with how little.”
The Seven Pillars of Io #
Io rests on seven fundamental concepts. Master these, and you’ve mastered the language:
1. Everything is an Object #
In Java or C++, primitives like integers and booleans aren’t objects—they’re special cases with different rules. In Io, everything is an object:
3 type println // Number
"hello" type println // Sequence
true type println // true
method() type println // Block
Even true
and false
are objects. Even methods are objects. This uniformity eliminates countless special cases.
2. Objects are Collections of Slots #
An object in Io is essentially a collection of named slots. Each slot can hold any value—data, methods, other objects:
person := Object clone
person name := "Alice" // data slot
person age := 30 // data slot
person greet := method("Hello!") // method slot
person friend := Object clone // object slot
Compare this to JavaScript, which has a similar model but complicated by functions, prototypes, constructors, and (now) classes. Io keeps it simple: objects have slots, period.
3. Computation is Message Passing #
This is perhaps Io’s most radical idea. In most languages, computation involves various mechanisms:
- Function calls:
sqrt(16)
- Method invocations:
list.append(5)
- Operators:
x + y
- Control structures:
if (x > 0) { ... }
- Assignment:
x = 5
In Io, all of these are just messages sent to objects:
sqrt(16) // send message "sqrt" with argument 16 to current object
list append(5) // send message "append" with argument 5 to list
x + y // send message "+" with argument y to x
if(x > 0, ...) // send message "if" with arguments to current object
x = 5 // send message "setSlot" to current object
This uniformity has profound implications we’ll explore throughout this book.
4. Objects Inherit from Prototypes #
Rather than defining classes as templates for objects, Io uses prototypes—objects that serve as templates for other objects:
Animal := Object clone
Animal move := method("Moving..." println)
Dog := Animal clone
Dog bark := method("Woof!" println)
fido := Dog clone
fido move // "Moving..." (inherited from Animal)
fido bark // "Woof!" (inherited from Dog)
There’s no distinction between “class” and “instance”—just objects cloning other objects.
5. Differential Inheritance #
When you clone an object in Io, the new object doesn’t copy all the slots from its prototype. Instead, it maintains a reference to its prototype and only stores its differences:
proto := Object clone
proto x := 10
proto y := 20
child := proto clone
child y = 30 // Only stores the difference
child x println // 10 (from proto)
child y println // 30 (from child)
This is memory efficient and enables powerful runtime modifications.
6. Everything is Modifiable at Runtime #
In Io, nothing is sacred. You can modify any object at any time, including built-in types:
Number double := method(self * 2)
5 double println // 10
// Even more radical - redefine addition!
Number + := method(n, self * n)
3 + 4 println // 12 (now multiplication!)
This flexibility enables patterns impossible in more restrictive languages.
7. Homoiconicity Through Messages #
Like Lisp, Io code is represented as data structures that can be manipulated by the program itself. But where Lisp uses lists, Io uses messages:
code := message(1 + 2)
code println // 1 +(2)
code name println // +
code arguments println // list(2)
This enables powerful metaprogramming without special syntax.
Comparing Philosophies #
To understand Io’s philosophy, let’s contrast it with mainstream languages:
Java: Protection Through Types #
public class BankAccount {
private double balance; // Protected from direct access
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
}
Java believes in protection—private fields, type checking, compile-time verification. The compiler prevents mistakes.
Python: Practicality and Conventions #
class BankAccount:
def __init__(self):
self._balance = 0 # Convention: _ means "private"
def deposit(self, amount):
if amount > 0:
self._balance += amount
Python believes in “we’re all consenting adults.” Protection through convention, not enforcement.
Io: Radical Flexibility #
BankAccount := Object clone
BankAccount balance := 0
BankAccount deposit := method(amount,
if(amount > 0, balance = balance + amount)
)
Io believes in complete openness. Any object can be modified by any code at any time. Power with responsibility.
The Cost of Simplicity #
Io’s radical simplicity comes with trade-offs:
Performance: Without static typing or compile-time optimization, Io can’t match the speed of C++ or even JIT-compiled languages like Java. Message passing has overhead.
Tool Support: IDEs can’t provide the same level of assistance without static types and fixed class definitions. Refactoring tools are limited.
Error Detection: Many errors that would be caught at compile-time in other languages only surface at runtime in Io.
Learning Curve: Paradoxically, Io’s simplicity can make it harder to learn. With fewer built-in concepts, you have to build more from primitives.
The Power of Simplicity #
But simplicity also brings power:
Understandability: You can understand the entire language. No edge cases, no historical baggage, no features that interact in surprising ways.
Flexibility: Patterns that require language extensions or complex frameworks in other languages are trivial in Io.
Expressiveness: With everything built from the same primitives, you can create abstractions that feel native to the language.
Exploration: Io is a playground for ideas that would be difficult to explore in more complex languages.
A Living Language #
Despite its small community, Io continues to evolve and inspire. Its ideas have influenced:
- JavaScript frameworks that embrace prototype-based patterns
- Ruby libraries that use method_missing for DSLs
- Newer languages like Factor and Ioke
More importantly, Io continues to teach programmers that our familiar concepts—classes, types, compilation—are choices, not requirements.
What’s Next #
In the following chapters, we’ll explore Io systematically:
- First, we’ll get Io running and write our first programs
- Then, we’ll dive deep into the object model
- We’ll explore message passing and method resolution
- We’ll see how control structures emerge from simple primitives
- We’ll build increasingly sophisticated abstractions
- Finally, we’ll tackle advanced topics like concurrency and metaprogramming
Along the way, we’ll constantly compare Io with languages you know, helping you see familiar concepts in a new light.
Ready to challenge everything you know about objects? Let’s begin.