Charlie Harvey

Io — Day Three

It all looked so easy, especially after the monster list of assignments on Io, day two. Well, appearances can be deceptive it seems. The place where I got stuck was on question three. Try as I might I couldn't override the colon operator as I wanted to do. It worked fine on the commandline. No problem at all. But once the code was in a file, no dice. I just saw variations of: Exception: Sequence does not respond to ':' Eventually, after a stentorian swearing session, I came across a post from Ola Bini on yahoo groups in a vaguely-titled thread called Question from "7 languages in 7 weeks". It seems that you can't override the operator table if it has already been used to read the current file. But, you can read your data from another file or using doString to get round this. Once I changed that everything suddenly became a bit more Ferris Bueller-like once more.

0. builder2.io

Enhance the XML program to add spaces to show the indentation structure.

There's plenty of approaches you could take to this. I just made a new method in a slot in the Builder object. I also put a tabchr variable in so that you could have \ts instead of spaces, which some people prefer and maybe easier to see in some cases. I hit one off by one error with the indentation depth, which of courshe should have started at -1 not 0. #!/usr/local/bin/io # Enhance the XML program to add spaces to show the indentation structure. Builder := Object clone Builder indent := -1 # Current level if indentation Builder tabchr := " " # Character with which to indent Builder forward := method( self indent := self indent + 1 writeln(indentstr(indent),"<", call message name, ">") call message arguments foreach( arg, content := self doMessage(arg) if(content type == "Sequence", writeln(indentstr(indent+1),content) ) ) writeln(indentstr(indent), "</", call message name, ">") self indent := self indent - 1 ) Builder indentstr := method( # Nb: Ben Nadel used a nice "repeated" method about which I knew # not on his post at http://www.bennadel.com/blog/2067-Seven-Languages-In-Seven-Weeks-Io-Day-3.htm. # It would have made this method less fugly had I known about it! indentlevel, indentstr := "" indentlevel repeat(indentstr := (tabchr .. indentstr) ) indentstr ) Builder ul(li("Io"),li("Lua"),li("Javascript"),li("Lisp")); Which yields something pretty readable. ~/code/seven_languages_in_seven_weeks/io/day_three$ ./builder2.io <ul> <li> Io <li> <li> Lua </li> <li> Javascript </li> <li> Lisp </li> </ul>

1. list.io

Create a list syntax that uses brackets.

I assumed that brackets ment curly brackets (I call them squigglies for some unfathomable reason). My answer was almost identical to the Map example earlier in the text. I couldn't figure out if I needed to make a more feature rich API. But to be honest it does everything a list does, so that's probably all it needs. #!/usr/local/bin/io # Create a list syntax that uses brackets # NB: I reckon we're thinking curly brackets here as that's what we used for # the Map earlier in this chapter. curlyBrackets := method( l := List clone call message arguments foreach(arg, l append(doMessage(arg)) ) l ) test_list := { "first", "second", "third" } test_list println That gives us ~/code/seven_languages_in_seven_weeks/io/day_three$ ./list.io list(first, second, third) Which is about right.

2. builder3.io

Enhance the XML program to handle attributes: if the first argument is a map (use the curly brackets syntax), add attributes to the XML program. For example: book({“author”: “Tate”}…) would print <book author=”Tate”>

This is where I got seriously stuck, as I mentioned in the intro. You'll notice that I retained much of my previous effort, which combined with the curlyBrackets Map example from earlier in the book made it pretty straightforward once I got past my block! #!/usr/local/bin/io # Enhance the XML program to handle attributes: if the first argument is a map (use the curly brackets syntax), add attributes to the XML program. For example: book({“author”: “Tate”}…) would print <book author=”Tate”> # Culled much of this from earlier in the chapter OperatorTable addAssignOperator(":" , "atPutProperty" ) curlyBrackets := method( m := Map clone call message arguments foreach(arg, m doMessage(arg) ) m ) Map atPutProperty := method( self atPut( call evalArgAt(0) asMutable removePrefix("\"") removeSuffix("\"" ), call evalArgAt(1) ) ) Map makeAttr := method( self map(attr,val, " " .. attr .. "=" .. "\"" .. val .. "\"" ) join ) Builder := Object clone Builder indent := -1 # Current level if indentation Builder tabchr := " " # Character with which to indent Builder forward := method( self indent := self indent + 1 args := call message arguments # println(args) # DEBUG write(indentstr(indent),"<", call message name) if(args first != nil and args first name == "curlyBrackets", write ( doMessage(args first) makeAttr ) args = args rest ) writeln (">") # now args has popped first arg off stack args foreach( arg, content := doMessage(arg) if(content type == "Sequence", writeln(indentstr(indent+1),content) ) ) writeln(indentstr(indent), "</", call message name, ">") self indent := self indent - 1 ) Builder indentstr := method( indentlevel, indentstr := "" indentlevel repeat(indentstr := (tabchr .. indentstr) ) indentstr ) # I found out that you can't override operators in the same file as # the operator table has already been constructed by the time you try # to override. So I read the next bit from a file. Or use doString cf: http://tech.groups.yahoo.com/group/iolanguage/message/12574 doFile("my_html_def.io") # That file simply says: # Builder ul(li({"class":"selected language","id":"IoLang","style":"text-align:left"}),li("Lua"),li("Javascript"),li("Lisp")) That little lot returns thus ~/code/seven_languages_in_seven_weeks/io/day_three$ ./builder3.io <ul> <li id="IoLang" style="text-align:left;" class="selected language"> Io </li> <li> Lua </li> <li> Javascript </li> <li> Lisp </li> </ul> Lovely.

Io: Some final thoughts

So, I guess that's it for Io. I liked the sparseness and regularity of the syntax and the ease of metaprogramming it. I tend to be the kind of person that programs by Google to an extent, so the comparitive newness of the language and smallness of the community were probably the major drawback for me. Tate reckoned that performance in simple single threaded applications may be an issue, I didn't push Io enough to hit those sorts of limits. One area which I shall try and explore some more and which Io is good at is concurrency. There's some introductory material on Coroutines, Actors and Futures which I may post on again in the future. I kind of missed the syntactic sugar of Ruby (and of course Perl) with Io, but I feel that I learned an interesting way of looking at and rather fun way of developing code. I can imagine Io being a perfect tool for knocking up quick commandline demos. And I look forward to hacking some concurrency. But its cider time for me now and I must say "¡Adiós Amigos!"


Comments

  • Be respectful. You may want to read the comment guidelines before posting.
  • You can use Markdown syntax to format your comments. You can only use level 5 and 6 headings.
  • You can add class="your language" to code blocks to help highlight.js highlight them correctly.

Privacy note: This form will forward your IP address, user agent and referrer to the Akismet, StopForumSpam and Botscout spam filtering services. I don’t log these details. Those services will. I do log everything you type into the form. Full privacy statement.