Archive for the ‘Io’ Category

Seven Languages in Seven Weeks — (Io Lesson 2)

In stark contrast to the first day’s sparse lesson this one was quite extensive. Not only that but I spent a bit of time playing with some of the examples as well. That being the case, let’s start a little bit before the formal lesson with a re-tooling of duck.io

// Here it is bound to a free method.
inheritanceGraph := method(obj, lst,
  if(lst == nil , lst = List clone)
  methodList := lst at(0)
  fullName := lst at(1)
 
  if(methodList == nil, methodList = List clone)
  if(fullName == nil, fullName = "")
 
  prototype := obj proto
  thisName := ""
  fullName = "#{prototype type}.#{fullName}" interpolate
  if(prototype == Object,
     writeln("----------------------------")
     writeln("Inheritance graph for #{fullName}\n----------------------------" interpolate)
     methodList = methodList reverse
     usedTypes := List clone
     currentType:=""
     methodList foreach(fullSlotName,
       currentType = fullSlotName split(".::") at (1)
       if(usedTypes contains(currentType) == false, 
         writeln(fullSlotName)
         usedTypes append(currentType)
       , nil)
     )
     writeln("----------------------------")
 
     ,
     prototype slotNames foreach(slotName,
       methodList append("#{fullName}::#{slotName}" interpolate)
     )
     inheritanceGraph(prototype, list(methodList,fullName))  
  )
)
 
Animal := Object clone
Animal speak := method("...Making an animal sound..." println)
 
Duck := Animal clone
Duck speak := method("QUACK!" println)
Duck walk := method("waddle..." println)
 
disco := Duck clone
inheritanceGraph(disco)
 
/*OUTPUT
----------------------------
Inheritance graph for Object.Animal.Duck.
----------------------------
Animal.Duck.::speak
Animal.Duck.::type
Duck.::walk
----------------------------
*/

I like the output from this more condensed reflection format a bit better than the book’s long form. The book’s original example gave far too much information, spread over far too much screen real estate. In fact, I’m glad the book mentioned reflection as an explicit example as I was a bit annoyed by using slotNames all by itself to determine the Object’s messages. This isn’t perfect. If you clone from an object instance rather than a “class” definition, you’ll get some weird results. Of course, the convention is that you wouldn’t normally clone an “instance” object but rather a “class” anyway.

Overall, I’m glad I wrote that code above… but I feel it is probably a bit overwritten. Could probably be shorter, or perhaps more idiomatic (as much as anything can be idiomatic in a language with little syntax).

Okay, now on to the problems. For the most part I’m happy with the answers but I couldn’t understand what question #6 was even asking for so unfortunately I had to skip it.

/*
Write a program to find the nth Fibonacci number.
fib(1) is 1 -- (1)
fib(4) is 3 -- (1,1,2,3)
As a bonus, solve the problem with recursion and with loops.
*/
 
// Using Recursion...
fib := method(input, 
 
  // as a matter of personal taste I dislike
  // optional "extra" params in a weak-typed
  // enviornment like this, so I chose not
  // to allow fib to accept an optional list...
  // but we *need* that optional list here in
  // order to find the answer using recursion.
  // Hence, there's an inner recurse method
  // to handle the fib.
  recurse := method(input, lst,
    if(lst == nil , lst = List clone)
    if(input > 1, recurse (input - 1, lst))
    if(input == 1 or input == 2, lst append(1) return(lst))
    lst append(lst at(lst size - 2) + lst at (lst size - 1))
    return(lst)
  )
 
  finalList := recurse(input)
  return (finalList at (finalList size - 1))
)
 
writeln(fib(1)) // returns 1
writeln(fib(4)) // returns 3
writeln(fib(10)) // returns 55
 
 
 
// Using a loop 
fib = method(input,
  i := 0
  l := List clone append(1,1)
  while(i <= input,
    if(i > 2, l append(l at(l size - 2) + l at (l size - 1)))
    i = i + 1
  )
  //writeln(" fib seq is #{l} " interpolate)
  return(l at (input - 1))
)
 
writeln(fib(1)) // returns 1
writeln(fib(4)) // returns 3
writeln(fib(10)) // returns 55

The Horseman is about to admit something that might be surprising. This is in fact the first time he’s ever actually coded a Fibonacci algorithm. Reasoning through Fibonacci itself wouldn’t be terribly hard on its own but I struggled a bit to express the algorithm in this “foreign” language. Obviously it works, and I’m happy enough with the outcome.

/*
  How would you change / to return 0 if the
  denominator is zero?
*/
Number originalDivision := Number getSlot("/")
Number / := method(n,
  if(n == 0, return(0), return(call target originalDivision(n)))
)
 
x := 10 / 5 
writeln(x)  // Returns 2
x = 10 / 0
writeln(x)  // Returns 0

This does solve the problem of how to return 0 when dividing by 0. Was it the “correct” solution? I wasn’t sure how else you were supposed to access the original message associated with the “/” operator from within the override without first assigning it to a placeholder message. In that sense it feels correct, though it also feels like an act of polluting the Lobby.

/*
  Write a program to add up all the numbers in a 
  2-dimensional array
*/
sum2DArray := method(array2D,
  // One way...
  array2D foreach(i, val, array2D atPut(i, val sum))
  array2D sum
)
 
row0:=list(1,2,3,4)
row1:=list(1,2,3,5)
row2:=list(1,2,3,6)
table:=list(row0,row1,row2)
writeln(table)
tableTotal:=sum2DArray(table)
writeln(tableTotal) // Returns 33

This one was easy as pie. I grant you, I didn’t bother with any error checking here. As a side-note, only after solving the problem this way did I discover the “flatten” message, which would have made the foreach loop completely irrelevant.

/*
  Write a prototype for a 2-dimensional list.
  The dim(x,y) method should allocate a list of
  y lists that are x elments long.
  set(x,y,value) should set a value and get(x,y) 
  should return that value
*/
 
Array2D := Object clone
Array2D dim := method(x,y,
  //writeln("x#{x} y#{y} self#{self}" interpolate)
  self table := List clone
  self myX:=x
  self myY:=y
  for(a, 0, y - 1,
    l:=List clone
    for(b, 0, x - 1, l append(nil))
    table append(l)    
  )
  //writeln(table)
)
Array2D set := method(x,y,value,
  if(x >= myX or x < 0 or y >= myY or y < 0, writeln("Array out of bounds.  x should be less than #{myX} and y should be less than #{myY}" interpolate);return(nil))
 
  table at(y) atPut(x, value)
 
)
Array2D get := method(x,y,
  if(x >= myX or x < 0 or y >= myY or y < 0, writeln("Array out of bounds.  x should be less than #{myX} and y should be less than #{myY}" interpolate);return(nil))
  table at(y) at(x)
)
/* wasn't sure what the bonus question 6 was trying to ask... */
 
a2d := Array2D clone
a2d dim(2,3)
a2d set(3,4,"foo") // "Array out of bounds. x should be less than 2 and y should be less than 3" nil
a2d set(1,1,"foo") // "foo"
writeln(a2d get(1,1)) // "foo"
writeln(a2d get(0,0)) // nil
writeln(a2d get(6,6)) // "Array out of bounds. x should be less than 2 and y should be less than 3" nil

Again, easy as pie. The only thing that caused me a little bit of problem was remembering the scope rules for the table, but that was hardly a problem. As I said before though, I had no idea what question #6 was even trying to ask. I didn’t even know where to start answering it because I simply had no clue what the requirement was supposed to be.

This next question uses the same Array2D object from the previous example.

writeln(a2d serialized())
 
/* write contents of matrix to a file */
f := File with("foo.txt")
f openForUpdating
f write(a2d serialized())
f close
 
/* and read back from a file into a new object */
copyOfa2dFromFile := doFile("foo.txt")
writeln(copyOfa2dFromFile serialized())
writeln(copyOfa2dFromFile get(1,1))

This serialization task was hard. No, it doesn’t look difficult to code and it is not difficult to code. What’s difficult is finding the documentation on serialization and deserialization. I was about 3/4 of the way through a custom serialization method before I wondered whether this was already available as part of the language. Io’s official website wasn’t much help with this.

At last, The Horseman rode forth into the final challenge of day 2:

/** Guessing game 
  I was attempting to play with Io's scoping in
  this example.  I wanted to have the Game object
  create a game instance that has all the 
  requisite methods and variables *without*
  defining any of thsoe variables or methods
  on the Game "class" object itself.
**/
Game := Object clone
 
Game make := method(cheatMode,
  // change the value of g below
  // to manipulate exactly *what*
  // your game is.  Maybe you
  // really do want the Game
  // object to be altered?  
  // in that case you'd supply 
  // self.  Or maybe you want to
  // "gamify" the sender or the
  // target?  You could set those
  // instead of just an Object clone
 
  g := Object clone
 
  g remainingGuesses := 10
  g targetNumber := Random value(99 + 1) floor()
  g lastGuessOffBy := 0
 
  if(cheatMode == true,  writeln("getting a random number ... #{g targetNumber}" interpolate))
 
  g prompt := method(
    if(remainingGuesses < 1, writeln("You lose."); return())
    writeln("Guess a number between 1 and 100")
    writeln("You have #{remainingGuesses} guesses remaining" interpolate)
    //writeln("target number is #{targetNumber}" interpolate)
    userInput := File standardInput readLine("Your guess : ") asNumber
    check(userInput)
  )
  g check := method(input,
    writeln("input was #{input}" interpolate)
    //writeln("answer is #{targetNumber}" interpolate)
    if(targetNumber == input, 
 
      writeln(" You win! ") ; return (targetNumber) ,
 
      remainingGuesses = remainingGuesses - 1;
      dist := (input - targetNumber) abs();               
      if(dist < lastGuessOffBy, writeln("hotter"), writeln("colder"));
      lastGuessOffBy = dist;         
      prompt
    )
  )
  return(g)
)
 
gameStartPrompt:= method(
  selection := File standardInput readLine("Play a game.  Do you want to cheat? Y/n ")
  if(selection uppercase == "Y", 
     Game make(true) prompt ; return(1))
  if(selection lowercase == "n",
     Game make prompt ; return(1))
  gameStartPrompt
)
 
gameStartPrompt
 
// Test to make sure that we haven't 
// altered the slots of the Game object
writeln(Game getSlot("prompt"))

The game itself was trivial to write. The only thing that truly gave me a fit was trying to find information on how to accept user input. In the end, I found the answer to that question from the blog of Ben Nadel. I was in no way expecting it to be part of the File object prototype. Of course, the little section on the Io website about “File” did not mention anything at all about this use for the Object.

As you can see, the way I wrote the Game object was a bit… weird. It didn’t take long at all to create the Game object just as a normal definition the same way as all the other objects from previous sections, but I wanted to really play around more with scope. What you see above is similar to the example shown at the end of the Ruby chapter in which you can dynamically add behaviors to Classes via mixins. Since I define the game object’s scope at the beginning of the method, I can change only that one line of code if I want to make that function do something else, like for example return a new Game instance, or perhaps to pass it an object that I wish to “gamify” in which case Game becomes more of a tool to apply ad-hoc behaviors to given objects.

So, at more than halfway through the Io chapter The Horseman can say that he’s glad that he didn’t simply ride past. This language feels like what ECMA could have been in a saner world. It’s minimal and won’t stand in your way when you want to do real work, yet at the same time its syntax for creation, instantiation, and definitions of behaviors is clear and unambiguous. Of course, it’s so minimal that you may end up defining a great deal of your own convenience methods simply to work as quickly as you might in other languages.

At the same time, defining one’s own syntax and language constructs is a mighty siren’s song. Perhaps my tune will change after I’m through the end of the 3rd day, but my current feeling is that I’d like to know more about this language and where it’s being used. From a purely academic perspective, I find myself drawn to Io’s simplicity and power for much the same reason as I am drawn to C. The main difference is that you can learn Io in a fraction of the time, with what feels like a fraction of the headaches… and of course with the downside that you only understand a fraction of the underlying mechanic.

1 Comment


Seven Languages in Seven Weeks – (Io Lesson 1)

The Horseman was surprised at the brevity of this lesson. In comparison to Ruby it was a mere stroll through the park. I suspect it has more to do with the brevity of the Io language’s syntax than a lack of topics to talk about. One very interesting thing I noted however was that day 1 for Io touched on topics that very closely relate to Ruby’s metaprogramming capabilities. I’m also going to come right out and say that there’s one particular feature that I really like about Io’s syntax that sets it apart from the ECMA script languages. In ECMA, the = operator is overloaded such as follows

var foo = {}; // dynamic untyped object...
foo.x = 6; // OVERLOADED.  If x exists on foo, assign it 6.  
          //If it does not, create x and assign 6

This kind of overloading is one of the most frustrating things about JavaScript, and why The Horseman vastly prefers never to use dynamic classes in ActionScript. In the absence of a compiler to tell you you’re doing something really stupid, this kind of overloading can easily cause you problems by introducing subtle, hard-to-track bugs related to typos and control-flow problems, and encourages the incredibly tedious overuse of hasOwnProperty() as a sanity check.

Io lays down the law and says “Oh no you don’t.”

foo = 0 
// ERROR! There's no foo slot in the program yet.  You can't assign to it yet.
 
foo = Object clone 
// ERROR!  Stop trying to assign until you create the foo slot!
// use := instead of =
 
foo := Object clone
// BINGO!
 
foo x = 0
// WHAT ARE YOU DOING?! There's no x slot on foo!
 
foo x := 0
// Perfect!  Now you can freely assign with =
 
foo x = 100
// See?  Isn't that much nicer?

So, with that out of the way…

The assignment was far more open-ended than any of the Ruby tasks. I wonder whether this has more to do with the language or the author’s own lack of familiarity with Io itself?

  • Run an Io program from a file
  • Execute the code in a slot given its name

Given requirements so simple, of course the Horseman had to make something a little bigger of it.

"Hello World" println
 
Foo := Object clone
Foo sayHello := method("Foo says hello" println)
foo := Foo clone
 
Foo sayHello
foo sayHello
 
/*
"First, I will create a count variable on the Foo prototype and 
check its value in the cloned instance."
*/
Foo count := 0
Foo count println // 0
foo count println // 0
 
/*
"And now I will set it equal to 3 in the prototype and check the instance's value.  Notice that the instance inherits the new value of count!"
*/
Foo count = 3
Foo count println // 3
foo count println // 3
 
/*
"Here we set the value of count on the foo instance to equal 6."
*/
foo count = 6
Foo count println // 3
foo count println // 6
 
/*
"Now we set the count value of the prototype Foo to 9 and print 
the value of the instance.  Notice that the instance NO LONGER 
REFERENCES THE Foo prototype's count!"
*/
Foo count = 9
Foo count println // 9
foo count println // 6
 
/*
"Simple increment (foo count = foo count + 1 .  += is not an 
operator in Io (though I wish += were the operator for creation 
rather than :=  )"
*/
foo count = foo count + 1
foo count println //7
 
"Simple multiplication (foo count = foo count * 20)" println
foo count = foo count * 20
foo count println // 140

Notice the precedence for what is returned from the various messages we send at the various times. It’s possibly a little surprising at first until it really clicks in your head what’s happening. But this is pedestrian. Surely I can think of something more fun to do with Io… something like this?

trace := method(output, "#{output}" interpolate println)
trace("A trace statement!  This is more like it!")

Aaah, that’s nice. A syntax that feels at least a little more familiar. While Io has very little in the way of operators and keywords of its own, the very interesting thing about this is that it means you’re largely free to create your own domain specific language for use in Io. It’s not going to stop you! So for example if you want some more options in regards to instantiation (maybe for example, with default values) you can create your own constructor. It should surprise absolutely nobody that The Horseman chose the word “new”

GeomPoint := Object clone
GeomPoint x := 0.0
GeomPoint y := 0.0
GeomPoint new := method(newX, newY, 
  obj := GeomPoint clone
  if(newX == nil) then(obj x = 0.0) else(obj x = newX)
  if(newY == nil) then(obj y = 0.0) else(obj y = newY)
  obj
)
GeomPoint coords := method(
  "(x=#{self x},y=#{self y})" interpolate
)
 
p1 := GeomPoint new coords println // (x=0,y=0)
p2 := GeomPoint new(10,20) coords println // (x=10,y=20)

We’re now seeing however, the unfortunate side of weakly typed variables and Io’s syntax (though I have to say that they appear to be statically typed given the various errors you receive when attempting incompatible coercions). Just look at all that ridiculous sanity checking to see if the vars are nil before attempting to assign. But no matter, once that’s over you can create new GeomPoint clones easily with new.

So come on, we can do more than just create a GeomPoint. What good is that on its own?

// This feels a bit more familiar...
DisplayObject := Object clone
DisplayObject x := 0.0
DisplayObject y := 0.0
DisplayObject name := "instance"
DisplayObject parent := nil
DisplayObject children := list()
DisplayObject getPosition := method(
  point := GeomPoint new(self x, self y)
)
 
// Assign each newly created DisplayObject with a new
// instance name of instanceX with X incrementing
DisplayObject idNumber := 0
DisplayObject new := method(
  obj := DisplayObject clone;
  obj name = "instance#{DisplayObject idNumber}" interpolate
  DisplayObject idNumber = DisplayObject idNumber + 1
  obj parent = nil
  obj children = List clone
  obj
)
 
// There doesn't seem to be a need for DisplayObjectContainer
// in this context so we'll just roll that into DisplayObject...
// For simply an abbreviated example, let's just have addChild...
DisplayObject addChild := method(displayObject,
  (displayObject type == DisplayObject type) ifTrue (
    if(displayObject parent != nil) then (displayObject parent removeChild(displayObject)) else (nil)
 
    displayObject parent = self
 
    self children append(displayObject)
  )
  displayObject
)
 
// and removeChild...
DisplayObject removeChild := method(childObject,
  oldSize := children size
  children remove(childObject)
  if(oldSize != children size) then(childObject parent = nil) else(nil)
  childObject
)
 
// And since we can now officially nest DisplayObjects inside
// a display list heirarchy.  Let's give them something to do... like convert
// localToGlobal GeomPoints and globalToLocal!
 
DisplayObject localToGlobal := method(geomPoint,
  if(parent == nil) then(geomPoint = geomPoint) else(
    geomPoint x = geomPoint x + self parent x
    geomPoint y = geomPoint y + self parent y
    geomPoint = parent localToGlobal(geomPoint) 
  )
  geomPoint
)
 
DisplayObject globalToLocal := method(geomPoint,
   parList := List clone
   parList append(self)
   tempParent := self parent
   while(tempParent != nil,
      parList prepend(tempParent)
      tempParent = tempParent parent
   )
   parList foreach(i,v, 
      geomPoint x = geomPoint x - v x
      geomPoint y = geomPoint y - v y
   )
   geomPoint
)

So, this should look really familiar to a lot of you. Flash display objects are arranged in a display list heirarchy. Now these Io DisplayObjects can do the same. Also, you can convert points from global into local space and back again.

mainDisplayObject := DisplayObject new
subDisplayObject := DisplayObject new
mainDisplayObject addChild(subDisplayObject)
 
trace(subDisplayObject parent)
trace(mainDisplayObject children at(0))
 
subDisplayObject x = 50
 
trace("Expecting local to global of x50 y0")
trace(subDisplayObject localToGlobal(subDisplayObject getPosition) coords)
 
mainDisplayObject x = 50
mainDisplayObject y = 25
 
resultPoint := GeomPoint new
 
trace("Expecting local to global of x100 y25")
resultPoint = subDisplayObject localToGlobal(subDisplayObject getPosition)
trace(resultPoint coords) 
// Look familiar?  Notice we get a return of GeomPoint from localToGlobal!
// for the rest, I'll use lazy shorthand (and break the rule of never putting code
// that results in actual execution inside a trace statement).
 
trace("Global point x0,y0 should be the exact negative of mainDisplayObjects 50/25")
trace(mainDisplayObject globalToLocal(GeomPoint new()) coords)
 
trace("Global point x0,y0 should be the exact negative of the cumulative 100/25 for this")
trace(subDisplayObject globalToLocal(GeomPoint new()) coords)
 
trace("Global point x125,y0 should traslate to x25,y35 here.")
trace(subDisplayObject globalToLocal(GeomPoint new(125, 60)) coords)

All the tests passed muster. So what about the add/remove child methods?

 
trace("Who is subDisplayObject's parent?")
trace(subDisplayObject parent)
mainDisplayObject removeChild(subDisplayObject)
trace("After calling mainDisplayObject remove(subDisplayObject) who is sub's parent?")
trace(subDisplayObject parent)
trace("And does main have children?")
trace(mainDisplayObject children)
 
 
subSubDisplayObject := DisplayObject new
 
trace("create a new DisplayObject and add it as a child to subDisplayObject...")
subDisplayObject addChild(subSubDisplayObject)
trace("and add subDisplayObject back as a child to main...")
mainDisplayObject addChild(subDisplayObject)
 
trace("Now, make main add the newest clip as its own child.")
mainDisplayObject addChild(subSubDisplayObject)
 
trace("The result is that main should have two children now, and both children should have main as parent")
 
trace("main's children")
trace(mainDisplayObject children)
trace("sub's children")
trace(subDisplayObject children)
trace("subSub's children")
trace(subSubDisplayObject children)
 
trace("sub's parent")
trace(subDisplayObject parent)
trace("subSub's parent")
trace(subSubDisplayObject parent)

All the resulting traces were exactly as expected in my implementation.

I’m quite aware that there’s at least one bug in the addChild implementation (trying to add a parent as a child of a grandchild could get a little wiggy), but the goal isn’t to perfectly replicate Flash. Rather, the goal is to show how comparatively easy it is to build up a language around Io, and how it generally stays out of your way while you do it. Naturally, this implementation also lacks a crucial graphics component.

Alas, we can’t have everything.

No Comments


Seven Languages in Seven Weeks – (Io : Getting set up)

“Jeez, how do you even get Io installed?”

The Horseman was very nearly tempted to skip Io for a few reasons. Prototype languages just aren’t his thing, and the minimal syntax feels so barren. That made it even harder for him to muster the desire to get it running given that the install process requires a compile from source and comes with a ReadMe that doesn’t quite tell you everything you need to know. In fact, following it led to several errors that our intrepid hero could not quite decipher.

Fortunately for Io (and for you as well), The Horseman stumbled onto This excellent guide to installing Io on Ubuntu. It only left out one step at the very end…

Remember to run sudo ldconfig after you successfuly run ./build.sh install.

Now when The Horseman types io into his terminal, the Io interpreter jumps to his beck and call.

horseman@horseman:~/7l_in_7w/io$ io
Io 20090105
Io> 8 + 8
==> 16

And we’re off!

Tags: ,

No Comments