Io

It seems everyone on the web is talking about the language Io at the moment. I wonder what started this... Anyway, lest we be left out of the fun, please share your impressions if you experimented with Io.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Reflections in the blogosphere

I haven't seen where everyone on the web is discussing Io, but I did notice why's post Io Has A Very Clean Mirror, also discussed on reddit.

reddit tends to cause flash language fads

One good blog entry about a language spawns a few more entries about people trying out that language, then people are googling for more information and submitting stories they find...and so on.

You say that like it's a bad

You say that like it's a bad thing...

It's great for getting more

It's great for getting more exposure for little known languages, but it doesn't mean that people are actually using those languages.

or...

Or understanding them, for that matter.

Of course... But reflecting

Of course...

But reflecting on the previous two posts, I now wonder: isn't there usually a reverse correlation between being widely used and being widely understood?

At the high end of understanding, no.

I'd wager there are probably more C++ gurus in the world than Haskell gurus, simply because the number of C++ users is so much higher.

The ratio of gurus to mortals tends to be higher for non-mainstream languages, however. (And for "toy" languages with a single user, the ratio is 100%. Or zero.) People will learn C++ or Java simply because it will get them employed; many working programmers in these languages have only sufficient understanding in the language to keep the job they have. People who invest the time to learn Haskell do so for other reasons, and are often motivated to become more skilled in it.

OTOH, if you intend "widely understood" to mean "well-understood by a signficant fraction of the language's community", then I would answer your question in the affirmative.

if you intend "widely

if you intend "widely understood" to mean "well-understood by a signficant fraction of the language's community", then I would answer your question in the affirmative.

That's what I meant.

Good / Bad

The Good:
The language itself is very interesting. For dynamism it's probably close to unmatched. Arguably has macros, even though it lacks a LISP or concatenative syntax, literally everything is modifiable at runtime, uses a bit of strange style of OOP not seen very often (prototype based, differential inheritance). As a language, it's very interesting to at least take a peak at.

The Bad:
The implementation is not the greatest in the world, it typically runs slower than other "scripting" languages, particularly for things like math intensive applications. For dynamic things, not many languages can match it, though. The language's designers and contributers are rather strongly opinionated (who isn't). Often sacrificing efficiency and safety for flexibility and unconstrained dynamism. The GC is claimed to be incremental, though as stated before here, the implementation isn't really incremental. Another thing, is the implementation is rather unstable, which can be a stumbling block for a lot of things.

All in all, I think it's worth a peak, but maybe not much more than that.

it typically runs slower

it typically runs slower than other "scripting" languages, particularly for things like math intensive applications.

Their microbenches imply greater than Python efficiency with vectors. Their other microbenches imply the same trend. I'd like to see how Io stacks up in the great language shootout to have a more objective measure. It's dynamism is impressive however, even though the dynamism leaks authority like a sieve.

Indeed..

I've seen articles stating that Io's vector efficiency exceeded C++'s, even on non-Apple machines. On Apple computers Io makes use of the C vector SIMD libraries. It's important to note, however, that Io's vectors are strictly float arrays and lack much of the dynamism of the rest of the language.

not sure

even though the dynamism leaks authority like a sieve.

I'm not sure what you mean by "leaks authority." Could you explain?

The Shootout

I'd like to see how Io stacks up in the great language shootout to have a more objective measure.

http://shootout.alioth.debian.org/sandbox/io.php

All of the usual disclaimers apply.

I'm not sure what you mean

I'm not sure what you mean by "leaks authority." Could you explain?

I thought someone might ask. Take blocks for instance. A block provides the Call object which responds to the 'sender' message, which, if I understand correctly, returns the locals of the calling context. That's a gross violation of both referential transparency, which ultimately impedes compositionality, and capability security, which compromises integrity.

[Edit: to clarify, that 'feature' is certainly a powerful, and potentially useful facility, I just don't think it's a good idea for large-scale software.]

I see. I think I was just

I see. I think I was just thrown off by the wording. Wasn't really sure what it meant to "leak" authority. Thanks :)

I've seen the "leaks

I've seen the "leaks authority" terminology used in contexts where authority is transmitted silently, and thus often uninentionally. For instance, returning a subtype C of B which adds authority to the declared type B also "leaks" authority. A client may at some point simply cast it to a C and access that additional authority, which is probably not what the original code written with B in mind had intended.

To me, accessing the caller's context as in Io is silent and surprising to anyone whose programmed in any call/return or lexically scoped language, which I think qualifies as most people. To me that qualifies as a leak, since malicious code somewhere down the call chain could theoretically jump all the way back up and modify some state it wasn't supposed to have access to. Perhaps I'm being too loose with my terminology though.

Issues

The dynamism of Io is arguably about as strong as you'll find. (How much of this is actually needed is another question.) If this is your number one concern, look no further.

Io does have a number of problems though.

1. Implementation quality is a concern, as previously mentioned. It's less than stable and very slow. That said, the model is fundamentally an expensive one, so it isn't clear how much the speed can be improved.

2. Io has Smalltalk-style blocks. However, due to the extreme reflective nature of the language, they're too expensive to use. Creating a block often results in a huge amount of memory being retained. Accordingly, much Io code (including the standard library) avoids the use of blocks. Methods like 'map' that would normally take a block instead take an expression. The 'map' method then evaluates the expression in the context of the caller. I find this quite clunky and prone to error. It is also less flexible in a lot of cases, and as a result, you find yourself manually passing message objects and associated context objects around in which to evaluate them.

3. Scoping in Io is resolved by traversing a directed graph. This is very slow, but also very confusing. Take this simple example:

Foo := Object clone
Bar := Object clone
Foo do(
   x := 5
   Bar do(
      y := 10
      z := x
   )
)

The above code will actually throw an exception because 'x' is not visible to Bar. This has been an ongoing problem for Io, and despite several attempts to resolve it, no satisfactory solution has been found. Some sort of 'lexicalDo' is needed to replace the current 'do' mechanism. Io's delegation can be very tricky in practice.

4. Bugs are very difficult to track down. The high amount of runtime code manipulation makes things difficult. Stack traces aren't useful. Methods incorrectly supplied with too many arguments simply ignore them. Et cetera.

5. It isn't at all clear which methods mutate the receiver and which return a new object. You might inspect the List object and notice it has a sort method, but short of trying it or checking the reference, there's no way to tell if it will return a new list or mutate the list receiving the message. This is aggravated by some seemingly odd choices as to which methods mutate and which don't.

6. There is currently no module system. Issues related to the delegation mechanism may make this difficult to solve for the same reason creating a 'lexicalDo' method is tricky.

Io is an interesting language. That said, unless you're obsessed with dynamic behavior and insist that everything in your life must be a first-class object, you'll have a hard time ignoring the fundamental problems.

Despite all this, I still like Io: It's simply a lot of fun. I'd not personally use it for anything serious, but it is my hope that some of these issues will be resolved in the future. Io has the potential to be a very nice alternative to languages like Python, Ruby, and Lua.

Blocks could be optimized a

Blocks could be optimized a little, and a lexical do isn't all that hard to do, it's a matter of what is acceptable for the community. I have a lexical do which is very adequate for my needs, but as any seasoned Ioer knows, I am more concerned with metaprogramming capabilities than really much of anything else -- I have other languages I use when I need speed or static semantics.

Io is about as dynamic as any language is, that is true, but it could be more dynamic (yes, really). There is one addition, a hook into slot lookup that could make Io as dynamic as any language could get -- allowing you to redefine semantics at runtime.

With respect to stack traces being useless, that isn't really the case; depending on what you are doing, they can be useless, but as a general rule, they are mostly useful for what most people will be doing with the language.

Since objects are namespaces, no module system needs to exist, the same functionality is built into the language, it's all a matter of convention. The only thing that is missing from what Io has now that would make up a module system, is the version control mechanism, which could be tagged on each object, at the additional cost of a word or so per object -- which depending on how many objects you have in your system, could mean a lot of extra memory based on the current implementation (alternative implementations could reduce the total memory footprint down to as few as 13 bytes, at the cost of some speed which could be made up for in other ways).

I don't see how supplying too many arguments and silently ignoring them is actually a bad thing. It's up to the method/block to decide what to do with additional arguments which aren't specified in formal parameters, which to be honest, is how it should be in a dynamic language.

jer

Amazing Example of Dynamic Io

Have a look at this neat example for adding something like a 'const' keyword to Io. I think that it's amazing that you can do this in Io at the language level rather than in the interpreter itself. You could use similar techniques to do method in-lining, partial-evalutation, JIT'ing, lazily evaluated macros, etc.

Constant = Object clone do (
  type = "Constant"

  init = method(msg,
    self msg = msg

    self activate = method(
      thisMessage setName(msg asString)
      msg
    )
  )
)

const = method(_obj, Constant clone(_obj));

// Let's try it out:

// Make PI a regular number

PI = 3.1415926

// Make b a method that uses it
b = method(PI+PI)

write(b,"\n") // -> 6.283185
// Inspect b's "source" code
write(getSlot("b") code,"\n") // -> block(PI +(PI))

// Make PI a constant

PI = const(3.1415926)

write(b,"\n") // -> 6.283185
write(getSlot("b") code,"\n") // -> block(3.141593 +(3.141593))

// Still works but when we look at the code of 'b' we see that
// the PI's have been replaced with PI's value!!!


From: http://tech.groups.yahoo.com/group/iolanguage/message/953

Is such dynamism effective in large-scale software engineering?

There is no doubt that Io is very flexible, but is such dynamism effective, or even desired, in large-scale software engineering or mission-critical software?

I have heard that while dynamic languages allow programs to be developed interactively (and thus shorten the development time), it's hard to change such programs, because every time you change something you can not be sure that something else is not broken until you run all the tests from the beginning...which means that for large-scale projects, such an approach might not be effective.

You're right, it's a very

You're right, it's a very hard sell for such tasks... However, dynamic languages can often be used, with great success, as "glue" languages between some lower level functionality (i.e., a 3D rendering engine) and a frontend display (i.e., a map) in a program like a 3D game. In such cases, using a dynamic language is often desired. To be honest, I would not use Io as anything more than a control/tool language glueing pieces of code together, not that I haven't used it for more (even much more). But since fall of 2003, I have not used Io, nor will I see myself in the future using Io, in anything more than such. Definitely not as a primary language in a large scale software project.

My favorite Io features.

I've done a moderate investigation into Io, having co-authored IoPEG (which isn't fully finished). As part of that, I kept a few notes on things that were interesting to me while learning it:

* Things that surprised me
* Random nuggets of info

Two things that I liked best about Io:

1) Explicit access to and enumeration of 'local' variables, as slots in an object that can be passed along or accessed in the calling scope.

2) The ability to inspect the 'syntax tree' before evaluating it. Among many other things, this let me write a debug function where I can do:
p( any valid io code here )
and have it create the string:
"any valid io code here: {the result of calling the code}"

In many other scripting languages I frequently write redundant/non-DRY debug code like:

output( "People.length: " .. People.length ) -- Lua
p( "People.length: #{People.length}"         # Ruby

Io is the first scripting language that has let me skip that (without having to do something silly like pass the code to evaluate as a string and then eval that).