Lazy Bricks, Lazy Mortar
Here’s a bit more Io. Don’t feel obligated to spread this stuff around. I like keeping things here obscure. After RedHanded, it’s nice to have a bit smaller crowd. And this stuff is just written for the few dedicated readers who don’t mind travelling Wherever.
Previously on Hackety Org, the topic was how you can get Io to reflect on its own code. In the parse tree, everything is a message. You can walk through a block and take it apart. The mortar is still soft, so you can move the bricks around.
Here’s a stack of bricks right here:
Builder html(
head(title("Lazy Bricks, Lazy Mortar"))
body(
div(
p("Here's a bit more Io...")
p("Previously on Hackety Org...")
)
div(
p("Adieu, friends and uncles.")
)
)
) print
So, the parse tree is all messages. Io looks at this and sees an html
message with one large argument: all that code inside the parens. That argument is a series of messages as well: head
and body
.
Most languages would just run all the messages and then get back to you afterward. But just like Neo, pausing time and plucking bullets from the atmosphere, Io gets nice and slow and lazy. We can step through the tree and run each message by hand.
Builder := Object clone
Builder forward := method(
tag(call message name, call message argAt(0))
)
This forward
method intercepts all messages. So the html
message is going to hit that slot.
One vital bit here: the method lists no arguments. Its argument list is empty. However, it really does take arguments. Normally, in Io, you’ll use html := method(arg1, arg2, ...)
to tell the method to receive two arguments. This would unpause The Matrix, though, and run all the messages like languages normally do.
If you send arguments to a method (or a block) without naming them, then Io will go lazy on us. It’ll attach those arguments to our Call object, but it’ll skip actually running them.
So, the code call message name
and call message argAt(0)
gets the method name and the arguments from the Call object.
Io> call message name
==> html
Io> call message argAt(0)
==> head(title("Lazy Bricks, Lazy Mortar")) ;
body(div(p("Here's a bit more Io...") ;
p("Previously on Hackety Org...")) ;
div(p("Adieu, friends and uncles.")))
See, all those messages are sitting around, waiting to be ignited! It’s our job to slap these bricks together, kid.
And I’ll bet it’ll take all of this arcane metaprogramming and snake charming, right??
Builder tag := method(name, nodes,
inner := ""
while(nodes,
if(nodes name != ";",
inner = inner .. if(nodes argCount > 0,
tag(nodes name, nodes argAt(0)),
doMessage(nodes))
)
nodes = nodes next
)
"<#{name}>#{inner}#{name}>" interpolate
)
A little tricky, but not too bad. We loop through each of the message nodes
and build a string as we go. The tricky part is inside the while
loop. The if
statement skips semicolon messages. All other messages have one of two fates: either recurse into tag
if there are more arguments or run the message.
You see, strings are messages, too. (Since they haven’t been turned into strings yet.) They are considered messages which ignore their arguments.
Io> "facts"("opinion")
==> facts
So the doMessage
is used to just get us the string, to reify it so we can add it to the bigger HTML string.
This all has given me much to think about. I haven’t been reaching for eval
in Io. (Where it’s called doString
.) Not as much spelunking for hidden caves to use for storage. All you got is slots and locals. Many limits, many restrictions. But, gladly, a whole lot of built-in messages.
alex
Do you think you could come up with some imaginative examples on how to do interesting things concurrently with Io? i.e., show how easy it is to go beyond your ruby “5ยข Concurrency” example with the async operator.
Matt Brubeck
Io looks like a perfect example of Smart languages and dumb parsers.
Brian Mitchell
All literal values in Io code are represented using messages. When messages are run one of two things happen:
1) The message checks a slot on itself (yes, messages are object) called cachedResult. If there is something set it will use it. Otherwise…
2) It will be dispatched to the target object. This is either explicitly given on the left side as an expression (possibly another message) or as an implicit object via the Locals object each scope runs its code in.
I’m looking forward to the entry that introduces removeAllProtos and forward or maybe setIsActivatable. ;-)
Moritz Heidkamp
Behold my Brackets module! Can you tell what it does?
Right, Rubyesque array literals and ECMAScriptastic Hash literals!
bug
Moritz: Yes, this is the kind of stuff that Io need more of, standard. Of course, you wouldn’t be able to redefine the brackets in another proto without messing things up…methinks Io needs to learn from Ruby about readability (and a pinch more sugar).
bug
Also, I apologize for forgetting that Io does indeed have hashes.
Djur
bug: But that’s not really an issue, because Io is primarily an extension/embedding language. The fact that it defines as little syntax as possible while leaving the door open for defining the meaning of that syntax is a plus.
Spongebob Squarepants
_Why…would love to have a poignant guide to Io once you’re done figuring it out :-)
jer
bug: I’d suggest that Io actually have less sugar than it does now, but retaining the hooks into the language so you can define the sugar as you need it. It’s not about dictating a syntax to anyone, it’s about keeping it as simple as possible, yet as flexible as it needs to be for other people to make it complex if they so desire.
_why
jer: It is really fascinating how Io has so many hooks that it doesn’t exploit itself. It’s like a patted-down schoolmarm whose subliminally teaching anarchy. Or like a very tiny congress that’s only there to make sure you have gobs and gobs of freedom. Do with it what you like, the language is yours to ruin, complements of the house.
bug
OK, Djur, that’s fair, and I guess now I like *jer*’s idea, too. It just almost seemed that Io was trying to be a better Ruby. It could be, if it wanted to, but then Ruby would be thrown out to the streets, rolling off clever one-liners for food. But Io doesn’t want that, I suppose. It wants you to make your own language from the bottom up. It’s a big ball of language clay, snatched from the skies of Jupiter. Of course, that means that once you mould your Io into a swan that winks slyly at everyone, your friend’s Io, which is now a monkey with glasses and a typewriter, can’t talk to yours. Ruby is the shiny red toolbox with mostly everything that mostly everyone needs, and also looks pretty. (and I wonder why Mac-ies like Ruby so much!)
steve
The compatibility of customizations issue can be somewhat solved by how io doesn’t have globals–so just put your customizations in your package’s namespace.
bleh
Why, you will notice that in time this blog will have a pretty great audience too. You did great with the Redhanded and people get attracted by your geniusity.
Comments are closed for this entry.