7 Languages in 7 Weeks. Week 2: Io Day 1

Io> Ferris live

So week 2 brings me (a week late) to a language I’ve never heard of before. As Ruby was Mary Poppins, so Io is, apparently, Ferris Bueller. I have a poor familiarity with Ferris Beuller’s Day Off so here ends all references to Ferris for this week’s posts.

Language Overview

Io is an object based prototype language. Everything is an object that receives messages and how the object responds to the message is dictated by its prototype. If a given object cannot respond to a message based on its prototype then the its type’s prototype is consulted (and so on). This will become clearer in a moment. This is the analogy of inheritance in a prototype language.

Like Ruby, Io is an interpreted language. After installing the interpreter and supporting libraries, statements can be entered directly into the interpreter. To run programs from a file the interpreter can either be invoked on the command line or (if the host operating system supports this idiom) referenced at the start of the program file.

Running statements in the Io Interpreter

[dan@home ~]$ io
Io 20090105
Io> "hello world" println
hello world
==> hello world
Io> 

Running an Io Program by Invoking the Interpreter

[dan@home ~]$ vi testing.io
[dan@home ~]$ io testing.io 
hello world

Running an Io Program by Specifying Interpreter in Source

[dan@home ~]$ echo '#!'$(which io) > testing2.io
[dan@home ~]$ cat testing.io  >> testing2.io 
[dan@home ~]$ chmod +x ./testing2.io 
[dan@home ~]$ ./testing2.io
hello world

Installing Io

Grab the sources to Io from the Io Github repo and unzip them into a build directory. There are a number of libraries required in order to build Io and the packaged components. I’m running Fedora 15 and needed to install the following packages to get a build that issued no warnings.

  • libffi-devel
  • freetype-devel
  • zlib-devel
  • ncurses-devel
  • libpng-devel
  • libtiff-devel
  • libjpeg-devel
  • gmp-devel
  • libxml2-devel
  • pcre-devel
  • openssl-devel
  • libglfw-devel
  • python-devel
  • rpm_build

Use the build.sh script in the extracted contents of the download to build and install Io:

[dan@home ~]$ ./build.sh 
[dan@home ~]$ sudo ./build.sh install
[dan@home ~]$ sudo ./build.sh LinkInstall

Finally you will need to update the locations used for finding dynamically loaded libraries. On my Fedora system this requires adding a new file referencing /usr/local/lib into the /etc/ld.so.conf.d/ directory and re-running ldconfig:

[dan@home ~]$ sudo echo "/usr/local/lib" > /etc/ld.so.conf.d/usrlocal.conf
[dan@home ~]$ sudo ldconfig

Io Resources

Given it’s youth, I found it surprising how much material is available on Io. A google for “io language” reveals quite a wealth of results.

Primary amongst these resources is Io’s home at http://www.iolanguage.com/. There are links from there to reference material and a useful wiki. From the wiki there are links to a useful page of samples and a style guide.

And as a sign that the language has surely “arrived”, Stackoverflow has an iolanguage question tag.

Exercises

Typing

Io is a strong but dynamically typed language. By adding slots we can provide implementations of expected methods. We can see this with a simple example:

[dan@home ~]$ io
Io 20090105
Io> 1 + 1
==> 2
Io> 1 + "two"

  Exception: argument 0 to method '+' must be a Number, not a 'Sequence'
  ---------
  message '+' in 'Command Line' on line 1

Io> "one" + "two"

  Exception: Io Assertion 'operation not valid on non-number encodings'
  ---------
  message '+' in 'Command Line' on line 1

Io> "one" type
==> Sequence
Io> Sequence + := method(next, self .. next)
==> method(next, 
    self .. next
)
Io> "one" + "two"
==> onetwo
Io> "one" + 1
==> one1
Io> 1 + "one"

  Exception: argument 0 to method '+' must be a Number, not a 'Sequence'
  ---------
  message '+' in 'Command Line' on line 1

Io> 

Here we send the + message to two Number objects and we get the expected result. When we try this between a Number and Sequence we get an exception and ditto when we try it with two Sequences. Once we define a + against Sequence our tests work. Sort of. I included that final erroring case as it highlights that the message is going to a Sequence and not a Number. Adding a + to Number such that it would accept a Sequence proved a little beyond me at this stage.

Truth

Apart from nil and false it seems pretty much everything in Io evaluates to true.

Io> true and true
==> true
Io> true and false
==> false
Io> true and nil
==> false
Io> true and 1
==> true
Io> true and 0
==> true
Io> true and ""
==> true
Io> true and "true"
==> true
Io> true and "false"
==> true
Io> true not
==> false
Io> 

Slots

The slotNames message enables us to see what slots are available on a given object:

Io> Object slotNames
==> list(newSlot, ownsSlots, isError, foreachSlot, currentCoro, <, removeAllSlots, list, for, doString, uniqueHexId, clone, become, write, evalArgAndReturnNil, serializedSlots, isNil, method, block, pause, isActivatable, deprecatedWarning, isLaunchScript, coroWith, evalArg, uniqueId, ?, actorProcessQueue, do, in, setProto, super, writeln, setSlot, !=, inlineMethod, doRelativeFile, removeAllProtos, coroDo, asyncSend, continue, stopStatus, ancestorWithSlot, print, protos, evalArgAndReturnSelf, actorRun, not, type, and, return, break, slotSummary, >, message, ==, serialized, slotNames, ifNonNilEval, asSimpleString, hasLocalSlot, while, updateSlot, switch, perform, returnIfError, asString, hasSlot, try, returnIfNonNil, hasProto, prependProto, getSlot, wait, justSerialized, hasDirtySlot, thisContext, removeProto, appendProto, println, lazySlot, loop, slotDescriptionMap, launchFile, .., relativeDoFile, serializedSlotsWithNames, compare, , yield, setSlotWithType, init, resend, isTrue, lexicalDo, or, doFile, argIsActivationRecord, raiseIfError, ancestors, isIdenticalTo, ifNil, ifNilEval, performWithArgList, cloneWithoutInit, contextWithSlot, thisLocalContext, >=, if, isKindOf, memorySize, <=, ifNonNil, coroFor, thisMessage, apropos, @, getLocalSlot, ifError, markClean, coroDoLater, slotValues, -, doMessage, proto, setIsActivatable, futureSend, removeSlot, shallowCopy, handleActorException, @@, setProtos, argIsCall)
Io> Person := Object clone
==>  Person_0x82f9b60:
  type             = "Person"

Io> Person slotNames
==> list(type)

The proto will list all the slots available to an object via its prototype.

A Note on Assignment Operators

Io has 3 operators that play a similar role:

  • =
  • :=
  • ::=

The first is assignment to an existing slot. An exception is raised if the slot is not present. This stackoverflow answer deals nicely with the difference between the second two.

Advertisement