Introduction to the Io Programming Language
Author: Nicolaas A. Scheltens
CPS 499-03: Emerging Languages, Spring 2017
Key language concepts in Io
- Pure object-oriented language: everything is an object.
- Prototype-based object model;
classes and instances are indistinguishable.
- Objects communicate through messages.
- Uses the Actor model of concurrency.
- Influenced by Smalltalk.
- No pointers.
Objects
Everything in Io is a object: integers, booleans, floats, and messages.
All entities are objects that can be
passed to other objects through messages, which are also objects.
- there are no pointers, or all object have distinct pointers.
- all created objects are called prototypes or instances.
- all objects contain a list of slots or key/value pairs.
- one root of the inheritance hierarchy with the name Object.
Example new prototype creation:
Io> Animal := Object clone
==> Animal_0x1e95638
type = "Animal"
All new prototypes create a new type with
the values being the name of the object. Instances inherit the type
of the prototype from which they where cloned.
When an object receives a message, it searches its slots for a match. If no match is found,
then the object sends the message to its prototype. If a message
is received, and it does not have the correct slot,
and none of its prototypes contain the correct slot,
then an error is thrown. This is called dynamic binding.
- All prototypes are stored in the Lobby object.
- Methods can be assigned to object slots like any other assignment.
Lists and Maps
Io has two types of collections: list and maps.
Io> Alist := list("some","things")
==> list("some","things")
The following are useful list slots.
- Alist size: returns size
- Alist append("more"): adds the value to the end of the list.
- list(1, 2, 3) average: averages integers or floats.
- list(1, 2, 3) sum: sums integers or floats.
- Alist at(1): return element at value.
- Alist pop: removes last element in list, returns element.
- Alist prepend("A"): adds element at the front of the list.
- Alist isEmpty: returns true or false if the list is empty.
Maps, on the other hand, are built by cloning the map object.
- add elements by using atPut(key, value).
- get a value by using at(key).
- asObjects: returns the map as slots.
- asList: returns the map as a list of lists.
- keys: returns the keys of the map in a list.
Concurrency
Io uses the Actor model of concurrency. Each actor
is modeled as a coroutine.
Io> AObject waitRoutine := method(wait(3);"A done waiting - " print)
==> method(
wait(3);writeln("done waiting")
)
Io> BObject waitRoutine := method(wait(2);"B done waiting - " print)
==> method(
wait(2);writeln("done waiting")
)
Io> AObject @@waitRoutine;BObject @@waitRoutine; wait(4);"Main" print
B done waiting - A done waiting - Main
==> nil
The program above creates two objects and starts both. Even though
AObject is declared first, BObject still finishes before
AObject because we started each (approximately) at the same time.
- the @@ operator
creates an actor that will run the following object.
- yield can be used to halt an actor.
- actors will automatically yield after they have sent a message.
A Synchronization Barrier
Barrier := Object clone
Barrier clientNum := 0
Barrier clientList := List clone
Barrier clientArrive := method(clientName,
clientList append(call sender)
"#{clientName} has arrived at the barrier" interpolate println
clientNum = clientNum - 1
if(clientNum == 0, done)
)
Barrier done := method(clientList foreach(v, v leaving()))
Client := Object clone
Client cnum ::= 0
Client ready := method(
wait(2)
Wild
Barrier clientArrive("Client#{cnum}" interpolate)
)
Client Wild := method(if(cnum%2 == 0, wait(Random value(3))))
Client leaving := method("Client#{cnum} is leaving the barrier" interpolate println)
"Enter how many clients" println
snums := File standardInput readLine
nums := snums asNumber
Barrier clientNum = nums
for(i,1,nums,
iClient := Client clone setCnum(i)
iClient @ready()
"Started a client"println
)
Coroutine currentCoroutine pause
Matrix Multiplication
Mat := Object clone
MatMult := Object clone
ProcessFile := Object clone
f := File with("Matrix.txt")
f openForReading
ProcessFile inList := f readLines
ProcessFile build := method(
for(a, 0, (inList size) - 1,
if(a == 0,
s := inList at(a) split
if(s at(1) != s at(3), Exception raise("Can not Multiply"))
Mat height = s at(0) asNumber
Mat width = s at(4) asNumber
buildMat2
builddList
)
if(a > 0 and a < (Mat height) + 1,
s := inList at(a) split
tList := List clone
for(b, 1, (s size - 2),
tList append(s at(b) asNumber)
)
Mat mat1 append(tList)
)
if(a > (Mat height) + 1,
s := inList at(a) split
for(c, 1, (s size - 2),
Mat mat2 at(c - 1) append(s at(c) asNumber)
)
)
)
)
ProcessFile buildMat2 := method(
x := List clone
for(d, 1, Mat width,
x append(List clone)
)
Mat mat2 = x
)
ProcessFile builddList := method(
for(e, 1, Mat height,
Mat dList append(List clone)
for(f, 1, Mat width,
Mat dList at(e-1) append(f)
)
)
)
Mat height := 2
Mat width := 2
Mat mat1 := List clone
Mat mat2 := List clone
Mat dList := List clone
Mat placeAtd := method(h, w, v, dList atPut(h, dList at(h) atPut(w, v)))
MatMult getNum := method(alist, blist,
x := 0;
for(i, 1, alist size,
x = x + ((alist at(i-1)) * (blist at(i-1)));
x println;
)
)
MatMult placeAt := method(h, w,
wait(2)
v := getNum(Mat mat1 at(h), Mat mat2 at(w))
Mat placeAtd(h, w, v)
)
ProcessFile build
Mat mat1 println
Mat mat2 println
for(i, 1, Mat height,
for(b, 1, Mat width,
nMatMult := MatMult clone
nMatMult @placeAt(i-1, b-1);
"starting" println
)
)
while(Scheduler yieldingCoros size > 1, yield)
f close
Mat dList println
The following is an example of an input file for the prior program.
3 3 x 3 3
[ 1 2 3 ]
[ 4 5 6 ]
[ 7 8 9 ]
[ 10 11 12 ]
[ 13 14 15 ]
[ 16 17 18 ]
Reflection
In Io, any object/class can be expanded or modified by the programmer.
- The following expression overwrites the print slot.
Object print = "im printing something"
- Due to its uniform syntax, there is little to no syntactic sugar in
Io.
- The OperatorTable is an object that contains all operators within
the language.
- All objects and their associated slots can be displayed by entering them
into the interpreter.
- New operators can be added using the addOperator message.
- Example:
Io> OperatorTable addOperator("!", 9)
...
9 | !
10 && and
11 or ||
...
Io> ! = method(bool, if(bool, false, true))
==> method(bool,
if(!bool, true, false)
)
Io> ! true
==> false
Io> ! false
==> true
Useful Links & Resources
Exercises
The following are some programming exercises that incorporate some essential
Io concepts:
- Create a prototype that reads a string of numbers from standard input and
transforms that string into a list of numbers. Create an
exponent slot that
accepts two integers as input and returns the first number raised to the
second number power. Send the exponent message to every integer in
the newly-created list using the last integer as the exponent and print the
modified list.
Examples:
Io> 1 2 3 4 5 2
==> list(1, 4, 9, 25)
Io> 2 3 7 1 5 3
==> list(16, 81, 2401, 1, 625)
- Use coroutines and the Actor model to create a
synchronization barrier. Read the number of
workers to be spawned as well as the capacity of the barrier as an integer
from standard input. The barrier must wait for all workers to arrive before
allowing any workers through the barrier.
Examples:
Io> 3
Started a worker.
Started a worker.
Started a worker.
Worker2 has arrived at the barrier.
Worker1 has arrived at the barrier.
Worker3 has arrived at the barrier.
Worker2 is through the barrier.
Worker1 is through the barrier.
Worker3 is through the barrier.
References
[PWC] |
J.A. Gallud, R. Tesoriero, and P. González. 2012.
Smalltalk: The leading language to learn object-oriented programming.
In Proceedings of the Federated Conference on Computer Science and
Information Systems. IEEE Computer Society Press,
Los Alamitos, CA, 839-840.
|
[RAOO] |
W. LaLondet, J. McGugan, and D. Thomas. 1989
The Real Advantages of Pure Object-Oriented Systems or Why Object-Oriented Extensions to C are Doomed to Fail.
In Proceedings of the 13th
Annual International Computer Software and
Applications Conference. IEEE Computer Society Press,
Los Alamitos, CA, 344-350.
|
[PWC] |
Z. Li and E. Kraemer. 2013.
Programming with Concurrency: Threads, Actors, and Coroutines.
In Proceedings of the IEEE 27th International Symposium on
Parallel and Distributed Processing Workshops and Ph.D. Forum.
IEEE Computer Society Press,
Los Alamitos, CA, 1304-1311.
|
|