= to assign a value to a slot on an object.
:= to assign a value on a slot or create a new value.
::= to assign a value to a slot, create setters for that slot or assign a new value.
I mentioned the concept of a slot here. This is a crucial feature of Io. It's quite similar to Ruby. You can send a message to an Io object and it will do 1 of a couple things:
Compute the arguments, inside out. These are just messages.
Get the name, target, and sender of the message.
Try to read the slot with the name of the message on the target.
If the slot exists, return the data or invoke the method inside.
If the slot doesn’t exist, forward the message to the prototype.
It looks like this in the code:
duck := Object clone duck quack := writeln("quack quack") duck quack
Here we are defining an
Object is the base prototypical object in Io. Say we sent a message to the duck object to figure out what kind of animal it was.
duck := Object clone duck type
You can see that we get
Object back. We didn't actually assign this slot to duck so where did Io get this value? This is where Prototypal Inheritance comes in. If that message isn't on the object, Io will pass that message to its parent object to see if it exists. So if we change the object that duck inherits from, that will be the first object that Io passes messages to.
Animal := Object clone duck := Animal clone duck type
This is how we can share behavior between objects:
Animal := Object clone Animal meow := writeln("meow") duck := Animal clone duck meow
Ducks shouldn't meow, but you get the idea.
A special feature of Io is how it treats evaluating its messages. Most languages will evaluate the parameters passed to values and assign those values to memory ahead of time. Io doesnt do this and it is an important destinction. An example that Bruce Tate uses in 7 Programming Languages in 7 weeks is defining an
unless := method( (call sender doMessage(call message argAt(0))) ifFalse( call sender doMessage(call message argAt(1))) ifTrue( call sender doMessage(call message argAt(2))) ) duck := Object clone duck isABird := true unless(duck isABird, write("Oh No, Im not a bird\n"), write("Yay, I am a bird\n"))
one is not two Yay, I am a bird true
Theres a lot going on here but the key point is you can pass any message into the first parameter of unless and this function will delay the execution of the parameters. You can see that a duck is a bird, so the
ifTrue block gets called, writing out
Yay, I am a bird. If Io was evaluating all the parameters,
Oh No, Im not a bird would have been written out.
Co-routines are useful for suspending your progams execution so that the thread can do something else. This is useful when you have to make some sort of asyncronous request or expensive task. You can
yield so that the asyncronous opertion happens and will be available when your program comes back to your function.
Bruce Tate gave a nice example in his book:
vizzini := Object clone vizzini talk := method( "Fezzik, are there rocks ahead?" println yield "No more rhymes now, I mean it." println yield) fezzik := Object clone fezzik rhyme := method( yield "If there are, we'll all be dead." println yield "Anybody want a peanut?" println) vizzini @@talk; fezzik @@rhyme Coroutine currentCoroutine pause
Here we define two regular objects both with methods that print things. You'll notice the
yield syntax. This is how you tell Io where your program will halt its execution and let other operations happen. The other important syntax is the
@@. This tells Io to execute that message in its own thread. As you can see the strings being printed are alternating from
fezzik back to
vizzini and then
fezzik. We have to through in
Coroutine currentCoroutine pause so our program doesnt exit before the threads are done.
Heres what happens when you run the code regularly:
vizzini := Object clone vizzini talk := method( "Fezzik, are there rocks ahead?" println yield "No more rhymes now, I mean it." println yield) fezzik := Object clone fezzik rhyme := method( yield "If there are, we'll all be dead." println yield "Anybody want a peanut?" println) vizzini talk; fezzik rhyme
Fezzik, are there rocks ahead? No more rhymes now, I mean it. If there are, we'll all be dead. Anybody want a peanut?
You can see that Io ignores the
Io has an extremely small footprint and flexible enough to describe an domain specific language. It's really cool to see how such different programming languages work.