Io: the language, not the moon

Published: 17 Jun 2016

This is the first in the Seven Languages series of posts and covers the Io language, a small prototypal language.

Let’s get this out of the way right now. I love Io. It’s amazing. The syntax is elegant and clean and incredibly extensible. You can pretty much rewrite Io to be whatever you want it to be which is really amazing. Want to parse JSON? Don’t bother with a parser… just extend the language to handle curly braces, square brackets, and colons. Done. It’s awesome.

I’ve really enjoyed getting to know it and felt like it was pretty simple to wrap my head around, possibly because the language I know best is also prototypal. Before we jump into the things I learned about the language that I thought were interesting let’s jump into the bad stuff. The things that were a pain and the things that made life hard.

Problems

You need Docker

A whole lot of the internals don’t work on OS X currently. It seems mostly tied to the way that the installer and OS X manage libevent, but I didn’t really dive deep enough to fix/figure it out. I compiled from source, I used the installer, I brew installed… none of it got me to a place that I could access things like Random or Socket (or any of their children).

That means minimally no web servers will startup on OS X and you won’t be able to do some of the homework around random number guessing.

The simple solution is to run all of your Io code in Docker. There is a good docker image here: https://hub.docker.com/r/nacyot/io-io/ that I’ve been using as a base and everything works like a champ in it. If I was you I would go straight to this solution and not even worry with installing it directly on OS X.

The main symptom I ran into was an error message that contained: "Library not loaded: /usr/local/lib/libevent-2.0.5.dylib". If you run into that beauty… just grab docker.

The Docs are… well…

When I was first learning Backbone I couldn’t make heads or tails of the documentation. It was written for someone who understood Backbone and not beginners. So once I made it over the hump and understood roughly what I was doing the documentation was amazing. While this is a slightly different problem than Io’s documentation it points out that documentation is hard.

One of the main problems with Io’s documentation is that it is sort of scattered. There is a "guide", a "tutorial" and a "reference" but it is not entirely clear what is where. For instance… if you want to know what the Number type is implemented on top of you need to go to the reference. (Number is a double usually implemented as a 64 bit floating point number) But if you want to understand the syntax of a number then you need to go to the guide because it isn’t in the reference. You get used to it… but the scattered nature seemed complicated to me.

The other problem with the docs is that they are at times completely inaccurate. For instance this section on ranges has a code example for using to() on a Number that doesn’t work at all. Ever. At least that I tried.

There is also very little about actually using Coroutines/Futures/Actors in practice. Or even what they would be useful for in the documentation. Some of the best discussion I found on them were in this presentation.

Even with that it took experimenting with them to realize that no matter what I did the program was still going to be completely single threaded on the CPU. Not single threaded in the node sense, where it spins out threads for long running/async tasks but single threaded. As in only 1 thread ever.

Tiny community is tiny

The community is tiny at this point. There are still releases happening occasionally, and still development happening on the github repo for the VM, but it is pretty infrequent. The best discussion resource I found was the old yahoo group that has essentially faded over the years.

That said Steve Dekorte hopped in on twitter and github and answered a couple of questions which was nice. I am pretty sure that if I really started writing something substantial that he would be a good source of information.

That said the overall impression I had of the community was that Io is a language that just never really found a broad enough niche. It was still looking for its killer application and was likely to remain a small hobby language until that happened.

Things I learned

Coroutines are not for what you think they are

Or at least not what I thought they were for. They don’t spin out a thread that rejoins the main thread on completion. This was a simple misunderstanding on my part because I was approaching this with in depth experience in V8/nodejs where this is handled pretty nicely.

They are really for preventing your long running task from blocking while other things could be processing. There is only one real thread and it handles everything. But if you need to hand control back to the main execution stream then they work pretty nicely.

Oh and the syntax is fantastic. The ability to change a normal function to an Actor/Future is phenomenal.

There was discussion about changing this part of the language so that they spun off as their own threads… but that seems to have never happened.

Performance

For my benchmark here I am using a parenthetical permutation problem that I have written in JS prior to this and seen implementations in Java, Ruby, and C. You can find it in the repo. I’ll be writing something similar in all the languages we tackle.

JS takes about 140-ish ms to crunch through permutation for 10 pairs of parentheses. C is about half that. Io is about 860-ish ms to perform the calculations recursively. So this kind of calculation is not an ideal fit for the language. When I tried pushing each iteration into an Actor the performance went down to 40+ seconds for the same number of permutation.

That was totally my fault though, as I was partially misunderstanding the sweet spot for coroutines in Io.

Web Server test

I am still writing this one… I’ll post details once I am done with it. Wanted to get it done but I am on to prolog and it’s crazy so I need to turn my attention there instead of here.

Parenthetical Permutations

This was pretty standard… it looks pretty much like any other recursive implementation. You can check it out in the repo. Not very fast. In fact it was really really slow. But, it worked as well as any other language’s recursive solution.

Method Arguments and Do blocks

This is actually a pretty awesome part of the language. When defining methods the last argument passed in is always the Do block. This holds true for loops and just about everything else as well. So creating named variable signatures are as simple as adding a comma separated list of names to your method declarations.

For instance: method( var1, var2, var3, writeln(var1 .. var2 .. var3))

The consistency of this makes it really easy to remember how to write things in the language.

Everything is an object with a prototype

Even the language. Well basically.

You can easily extend the language by adding slots to the OperatorTable lets you create handlers for new types of characters (for instance : or [] or {}). This is incredibly powerful and lets you make the language even more expressive than it already is.

On missing_method handlers!

I had forgotten how powerful these could be in the years since I was actively writing ColdFusion. There are entire frameworks in CF that use missing method handlers to function. Io has them… and they can be pretty awesome. Now I miss them in JS :-(

In conclusion

I like Io. Will I be using it tomorrow for the next web app of the future? Nope. Probably not. It has a place, but it isn’t something I am going to reach for everyday. It is a good stepping off point for other languages, and the Future/Actor are useful concepts to nail down because they are used by other languages as well.

No matter what I say though I can’t get past the simple beauty of this tiny little language. The code is just nice to look at. And to write.