Skip to content

Latest commit

 

History

History
544 lines (389 loc) · 10.5 KB

File metadata and controls

544 lines (389 loc) · 10.5 KB

Chapter 2: Getting Started with Io

The best way to understand Io is to use it. In this chapter, we'll install Io, explore its REPL (Read-Eval-Print Loop), and write our first programs. By the end, you'll have a feel for Io's syntax and flow.

Installing Io

macOS

If you're on macOS with Homebrew, installation is simple:

brew install io

Linux

On most Linux distributions, you'll need to build from source:

git clone https://github.com/IoLanguage/io.git
cd io
mkdir build
cd build
cmake ..
make
sudo make install

Windows

Windows users should use WSL (Windows Subsystem for Linux) and follow the Linux instructions, or use Docker:

docker run -it --rm stevedekorte/io

Verifying Installation

Once installed, verify Io is working:

$ io --version
Io Programming Language, v. 20170906

$ io
Io> "Hello, World!" println
Hello, World!
==> Hello, World!
Io> ^C

The REPL: Your Io Playground

Io's REPL is where you'll spend most of your learning time. Unlike compiled languages where you write, compile, and run, Io lets you experiment immediately.

Start the REPL by typing io:

$ io
Io>

The prompt Io> indicates Io is ready for input. Let's explore:

Io> 2 + 2
==> 4

Io> "Hello" .. " " .. "World"
==> Hello World

Io> 10 > 5
==> true

Notice the ==> prefix? That shows the return value of your expression. Everything in Io returns a value.

REPL Tips

  1. Multi-line input: The REPL detects incomplete expressions:
Io> if(true,
...     "yes" println,
...     "no" println
... )
yes
==> yes
  1. Previous result: Use _ to reference the last result:
Io> 100 * 2
==> 200
Io> _ + 50
==> 250
  1. Getting help: The REPL has built-in documentation:
Io> Lobby slotNames
==> list(Protos, _, exit, forward, set_)

Io> Number slotNames sort
==> list(%, *, +, -, /, <, <=, ==, >, >=, abs, acos, asin, atan, between, ceil, cos, ...)

Your First Io Program

Let's write the traditional "Hello, World!" program. Create a file called hello.io:

"Hello, World!" println

Run it:

$ io hello.io
Hello, World!

That's it. No class definitions, no main function, no boilerplate. Compare with Java:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Or even Python:

if __name__ == "__main__":
    print("Hello, World!")

Io just runs your code.

Understanding Basic Syntax

Io's syntax is minimal. Let's explore the basics:

Messages and Receivers

In Io, everything is about sending messages to objects:

"hello" size         // Send 'size' message to "hello"
==> 5

"hello" at(0)        // Send 'at' message with argument 0
==> h

"hello" upper        // Send 'upper' message
==> HELLO

Compare with method calls in Python:

"hello".upper()      # Python
"hello" upper        // Io - parentheses optional for no arguments

Arguments

Messages can have arguments, passed in parentheses:

"hello" at(1)                    // One argument
==> e

"hello" slice(1, 3)              // Two arguments
==> el

List append(1, 2, 3)            // Multiple arguments
==> list(1, 2, 3)

Operators are Messages

This is crucial: operators in Io are just messages with special precedence:

2 + 3          // Send message "+" to 2 with argument 3
2 +(3)         // Exactly the same thing
2 send("+", 3) // Still the same thing!

This uniformity means you can redefine operators:

Number + := method(n, self - n)  // Redefine + to subtract!
5 + 3
==> 2

(Don't actually do this in real code!)

Variables and Assignment

In Io, variables are just slots on objects. By default, you're working with the Lobby object:

x := 10        // Create slot 'x' on Lobby with value 10
x println      // Print it
==> 10

x = 20         // Update existing slot
x println
==> 20

y = 30         // Error! Slot doesn't exist
// Exception: Slot y not found

Note the distinction:

  • := creates a new slot
  • = updates an existing slot

This prevents accidental variable creation from typos:

counter := 0
countr = 1     // Error - probably a typo!

Compare with JavaScript's similar issue:

let counter = 0;
countr = 1;    // Creates global variable - probably a bug!

Control Flow

Io's control structures are methods, not special syntax:

If Statements

if(10 > 5,
    "Yes" println,
    "No" println
)
// Prints: Yes

Compare with Python:

if 10 > 5:
    print("Yes")
else:
    print("No")

Since if is a method, you can even look at its implementation:

Io> if
==> method(...)

Loops

// While loop
i := 0
while(i < 5,
    i println
    i = i + 1
)

// For loop
for(i, 0, 4,
    i println
)

// Times loop
5 times(i,
    i println
)

Creating Objects

Let's create our first custom object:

Person := Object clone
Person name := "Unknown"
Person greet := method(
    ("Hello, I'm " .. name) println
)

alice := Person clone
alice name = "Alice"
alice greet
// Prints: Hello, I'm Alice

Compare with Python:

class Person:
    def __init__(self):
        self.name = "Unknown"
    
    def greet(self):
        print(f"Hello, I'm {self.name}")

alice = Person()
alice.name = "Alice"
alice.greet()

The key difference: Io has no class definition. Person is just an object we're using as a prototype.

Methods

Methods in Io are created with the method function:

Calculator := Object clone
Calculator add := method(a, b, a + b)
Calculator multiply := method(a, b, a * b)

calc := Calculator clone
calc add(5, 3) println        // 8
calc multiply(4, 7) println    // 28

Methods have access to self (the receiver):

Counter := Object clone
Counter count := 0
Counter increment := method(
    count = count + 1
    self            // Return self for chaining
)

c := Counter clone
c increment increment increment
c count println    // 3

Lists and Iteration

Lists are fundamental in Io:

numbers := list(1, 2, 3, 4, 5)

// Iteration
numbers foreach(n,
    n println
)

// Map
squared := numbers map(n, n * n)
squared println    // list(1, 4, 9, 16, 25)

// Select (filter)
evens := numbers select(n, n % 2 == 0)
evens println      // list(2, 4)

// Reduce
sum := numbers reduce(+)
sum println        // 15

Compare with Python:

numbers = [1, 2, 3, 4, 5]

# Iteration
for n in numbers:
    print(n)

# Map
squared = [n * n for n in numbers]

# Filter
evens = [n for n in numbers if n % 2 == 0]

# Reduce
from functools import reduce
sum = reduce(lambda a, b: a + b, numbers)

Working with Files

Reading and writing files is straightforward:

// Write to file
file := File with("test.txt")
file openForWriting
file write("Hello, file!")
file close

// Read from file
file := File with("test.txt")
file openForReading
contents := file contents
contents println
file close

// Or more concisely
File with("test.txt") contents println

A More Complete Example

Let's build something more substantial—a simple to-do list:

// todo.io - A simple to-do list manager

TodoList := Object clone
TodoList items := list()

TodoList add := method(task,
    items append(task)
    self
)

TodoList show := method(
    if(items size == 0,
        "No tasks!" println,
        items foreach(i, task,
            ("  " .. (i + 1) .. ". " .. task) println
        )
    )
    self
)

TodoList complete := method(index,
    if(index > 0 and index <= items size,
        task := items at(index - 1)
        items removeAt(index - 1)
        ("Completed: " .. task) println,
        "Invalid task number" println
    )
    self
)

TodoList save := method(filename,
    File with(filename) openForWriting write(items asJson) close
    "Saved!" println
    self
)

TodoList load := method(filename,
    if(File with(filename) exists,
        items = Yajl parseJson(File with(filename) contents)
        "Loaded!" println,
        "File not found" println
    )
    self
)

// Usage
todo := TodoList clone
todo add("Learn Io") add("Build something cool") add("Share with friends")
todo show
//   1. Learn Io
//   2. Build something cool  
//   3. Share with friends

todo complete(1)
// Completed: Learn Io

todo show
//   1. Build something cool
//   2. Share with friends

Key Takeaways

Having written your first Io programs, you've probably noticed:

  1. Minimal syntax: No keywords for defining classes, functions, or variables. Everything uses the same message-passing syntax.

  2. Immediate feedback: The REPL makes experimentation effortless.

  3. Uniform model: Whether you're doing arithmetic, defining methods, or creating objects, it's all message passing.

  4. Flexibility: You can modify anything, even built-in types and operators.

  5. Simplicity: Programs are often shorter than their equivalents in other languages.

Exercises

Try these exercises to solidify your understanding:

  1. Number methods: Add a squared method to Number that returns the square of a number. Test it with 5 squared.

  2. String reversal: Create a method on Sequence (Io's string type) called reverse that returns the reversed string.

  3. Bank account: Create a BankAccount object with balance, deposit, and withdraw methods. Include protection against negative balances.

  4. FizzBuzz: Implement FizzBuzz in Io (print numbers 1-100, but "Fizz" for multiples of 3, "Buzz" for multiples of 5, "FizzBuzz" for both).

  5. Method chaining: Create a StringBuilder object that allows chaining: StringBuilder clone add("Hello") add(" ") add("World") toString

What's Different?

If you're coming from mainstream languages, here's what might feel strange:

  • No compile step: Your code runs immediately
  • No type declarations: Everything is dynamically typed
  • No class keyword: Objects are created by cloning
  • Operators aren't special: They're just messages
  • Everything returns a value: Even assignments and control structures

These differences aren't arbitrary—they all flow from Io's core principle of uniform message passing.

Moving Forward

You now have enough Io knowledge to explore the deeper concepts. You can:

  • Create and manipulate objects
  • Define methods
  • Use control structures
  • Work with collections
  • Read and write files

In the next chapter, we'll dive deep into Io's object model and understand what "everything is an object" really means.


Next: Chapter 3 - Everything is an Object