Io at a Glance — A Language a Day, Advent Calendar Day 23/24

Welcome to Day 23 of this year’s A Language a Day Advent Calendar. Today’s topic is introduction to the Io programming language.

About this ‘A Language a Day’ Advent Calendar

Andrew Shitov. A Language a Day

This article became a part of my book ‘A Language a Day’, which you can get in both electronic and paper format. Languages covered in the book: C++, Clojure, Crystal, D, Dart, Elixir, Factor, Go, Hack, Hy, Io, Julia, Kotlin, Lua, Mercury, Nim, OCaml, Raku, Rust, Scala, and TypeScript.

Learn more where to get the book

Welcome to Day 23 of this year’s A Language a Day Advent Calendar. Today’s topic is introduction to the Io programming language.

Facts about the language

  • Prototype-based, object oriented
  • Dynamically typed
  • A homoiconic language
  • Appeared in 2002
  • Website: iolanguage.com

Installing and running Io

To install Io, download one of the packages for your operating system.

To run a program, run io:

$ io helloworld.io

Hello, World!

Here is the minimum Hello, World! program in Io:

"Hello, World!\n" print

Alternatively, you can use println to add the newline instead of \n:

"Hello, World!" println

What happens in the Hello, World! program is you send the print message to the string. In essence, this is a keystone knowledge of the design of Io.

Variables

To create a variable, use the := assignment.

name := "John"
("Hello, " .. name .. "!") println

Notice the .. for string concatenation here.

There are also ::= and = forms, please refer to the Io guide for more details about them. ::= also creates a setter, while = raises exception when the slot does not exist.

Functions

To create a function, use method. Let us first create a function that takes no arguments.

greet := method("Hello, World!" println)
greet

In the second line, you call the earlier created function.

Now, let us add an argument by just listing it before the function body:

greet := method(name, ("Hello, " .. name .. "!") println)
greet("Alla")

A Factorial example

Here is a possible solution of computing a factorial:

factorial := method(n, if(n < 2, 1, n * factorial(n - 1)))

factorial(1) println # 1
factorial(5) println # 120
factorial(7) println # 5040

But there is a simple way, as the function that we need is already built in:

1 factorial println // 1
5 factorial println // 120
7 factorial println // 5040

Objects

Io implements the prototype-based object-oriented mechanism. To create a new object or a type, clone the Object object:

Person := Object clone

An identifier that begins with a capital letter is considered a type. Otherwise, it is an object.

Object fields, or, slots, are accessed by sending messages to the object. For example, let us state that a Person works in the X company:

Person company := "X"

Now, we can create (or clone) people working in this company, and set their own slots:

john := Person clone
john name := "John"
john age := 23

alla := Person clone
alla name := "Alla"
alla age := 22

Whenever you need to access data, do it in the same manner:

((alla name) .. " is " .. (alla age)) println
("She works in " .. (alla company)) println

This program prints:

Alla is 22
She works in X

Be careful not to accidentally send messages that has no effect. This can happen when you omit a punctuation or type extra characters.

("Works in" (alla company)) println 42

The output of this line of code is a single string "Works in".

Inheritance

Expressing inheritance is very easy, just clone a type and set the needed slots:

Person := Object clone

XPerson := Person clone 
XPerson company := "X"

YPerson := Person clone 
YPerson company := "Y"

Now, we have a type for people working in X and another type for those who work in Y.

john := YPerson clone

alla := XPerson clone

A Polymorphic example

Let us define the two types that are based on the Animal type. Just for diversity, let us add an unknown animal to the collection. That animal will be served but the info slot of the Animal type object.

Animal := Object clone
Animal info := "I am an unknown animal"

Cat := Animal clone
Cat info := "I am a cat"

Dog := Animal clone
Dog info := "I am a dog"

zoo := list(Cat clone, Cat clone, Dog clone, Dog clone, Animal clone)
zoo foreach(i, x, x info println)

In the foreach loop, the x variable loops over the zoo list items and it receives the info message, which returns a different string depending on a real type of the object.

As an exercise, modify the program to make info methods, for example:

Dog info := method("I am a dog" println)

Concurrency

Io offers support for coroutines and the scheduler, actors (which are objects having their own coroutine), and futures.

Let us use actors to implement the Sleep sort algorithm.

Sleep Sort

The main idea behind the following solution is to send an asynchronous message to an object. So, we define the Sorter type that has the sort method. To send the message (sort in our case) asynchronously, prefix it with @@.

data := list(10, 4, 2, 6, 2, 7, 1, 3)

Sorter := Object clone
Sorter sort := method(n,
    wait(n/10);
    n println
)

sort_me := method(n,
    s := Sorter clone;    
    s @@sort(n)
)

data foreach(n, sort_me(n))

wait(2)

Get more

Io is a very syntactically compact language. Its basics can be learned literary within minutes. To dive deeper, examine its documentation pages:

The source codes of this issue of the series are located on GitHub.

Next: Day 24. Factor

Leave a Reply

Your email address will not be published. Required fields are marked *

Retype the CAPTCHA code from the image
Change the CAPTCHA codeSpeak the CAPTCHA code