So I am on the final 'day' of the Io chapter in Bruce Tate's Seven Languages in Seven Weeks. This chapter focused on a couple of things, Domain Specific Languages (DSLs) and concurrency with Io's actors. This blog post will focus on dsl stuff and an implementation of mixins I did. Concurency is discussed in the next post.
Domain Specific Languages
The coverage of DSLs focused on ways to affect how Io parses certain symbols, as well as how to process arbitrary messages send to an object. The code below shows how to add a familiar square bracket syntax for lists in Io.
#Create a list syntax that uses square brackets
Object squareBrackets := method(
#simply return the *list* of arguments passed in
call message arguments
)
l := [1,2,3,4,5]
l type println # => list
l at(1) println # => 2
#define a square brackets index syntax on lists
List squareBrackets := method(index,
self at(index)
)
l[4] println # => 5
The method squareBrackets is called whenever Io encounters square brackets in the text of the code, the arguments to the method is a list of whatever is between the square brackets. Because we are simply trying to build a list, the implementation of this method is quite short, we simply return the list. We also add a squareBrackets method to the List proto to allow familiar square bracket list access. Io has similar methods for curly brackets '{}' and even parentheses '()'. The example in the book uses the former in conjunction with the ability to add new operators in Io to build a JSON like literal syntax for Maps. So that one can write
{
"Banana" : "Yellow",
"Apple" : "Red",
"Orange" : "Orange"
}
and have Io parse that into a Map object. The code for this is about 10 lines.
The other component to DSLs discussed was having Objects respond to arbitrary messages that are sent to them (that haven't already been defined as methods on the object). This takes advantage of the fact that when an object receives a message it doesn't know what to do with, it forwards it to its prototype(s). You can redefine the forward method to do whatever you want. This is much like ruby's method_missing method. Using this the author creates an XML builder object that can take messages that represent tags one wants to create and will print well formed xml, its pretty straightforward.
Implementing Mixins in Io
The exercises for day 3 weren't terribly exciting (and didn't touch concurrency at all), so I went ahead and did a few other things. The first was implementing ruby like mixins in Io. I thought i'd be using the forward method described above, but it turned out to be easier than that. I give you two implementations of mixins in Io.
The first approach I came up with was to iterate through the methods defined on the objects being mixed in and add them to the object doing the mixing. I find this approach pretty elegant and it gives us complete control over how the mixin operation works.
The second approach is even shorter and simply adds the mixed in object to the list of protos for the object doing the mixing. That way the objects regular forward method will take care of sending the messages to the mixed in object that defines their implementation. I think this is similar to how ruby implements mixins (by putting the module into the classes' inheritance chain). It also shows the flexibility of inheritance in a prototype based language like Io.
The example here is to use mixins to easily make objects comparable, my mixing the Comparator object and defining a compareTo method, the object now responds to <, > and == (<=, >= can easily be added as well).
As usual the code for this is on github. See io_day_three.io and io_mixins.io.