[Io] Let's party OOP-style!
Author |
Message |
wtd
|
Posted: Sat Nov 11, 2006 5:19 pm Post subject: [Io] Let's party OOP-style! |
|
|
What are these object things?
That's an object.
That's an object too. As is:
Everything's an object!
But objects have methods, right?
Darn straight!
code: | Io> 4 factorial
==> 24 |
And that just returns another object, so we can call a method on that.
code: | Io> 4 factorial println
24
==> 24 |
But what's really going on here?
Well...
Sends the "factorial" message to the object 4. In response, the method in the "factorial" slot of the target object is called.
We can, of course, put a new method in that slot.
code: | Io> 4 factorial := method(42)
==> method(42)
Io> 4 factorial
==> 42 |
What about binary methods?
code: | Io> 3 * 2 + 1
==> 7
Io> "hello" .. " " .. "world"
==> hello world
Io> "hello" .. " " .. "world" .. " " .. 42
==> hello world 42 |
Which are really just messages which take one argument.
code: | Io> 2 +(6)
==> 8
Io> 3 +(5) *(4.2)
==> 33.6 |
So, what about methods which take multiple arguments?
code: | Io> list(1, 2, 3)
==> list(1, 2, 3) |
Let's write a method.
code: | Io> sayHello := method("Hello" println)
==> method("Hello" println)
Io> sayHello
Hello
==> Hello |
As it happens, "method" is just a message being sent to Object. And here it's taking a single argument.
But if "method" is a method... how in the name of everything unholy does it do what it does?
This should immediately be evaluated, and the value submitted to "method".
But really, it's a Message object, and if we want, we can evaluate it at any time. This is how things like "method" work.
It's also how things like conditionals and loops work.
code: | Io> if(true, "Hello" print; " world" println, "Foo bar" println)
Hello world
==> world
Io> 1 to(4) foreach(v, v println)
1
2
3
4
==> 4 |
So, let's write a method that takes an argument.
code: | Io> sayHello := method(name, ("Hello, " .. name .. "!") println)
==> method(name, ("Hello, " ..(name) ..("!")) println)
Io> sayHello("Bob")
Hello, Bob!
==> Hello, Bob! |
There's nothing especially phenomenal about that.
But really, that's the same as:
code: | Io> Object sayHello := method(name, ("Hello, " .. name .. "!") println)
==> method(name, ("Hello, " ..(name) ..("!")) println)
Io> Object sayHello("Bob")
Hello, Bob!
==> Hello, Bob! |
So, sayHello is now a method of Object. And since every other object has Object as a prototype...
code: | Io> 4 sayHello("Bob")
Hello, Bob!
==> Hello, Bob! |
Isn't that neat?
We can even see that Object is a prototype of 4.
code: | Io> 4 hasProto(Object)
==> true |
So, obviously 4 doesn't itself have a slot to answer to the sayHello message. Since it doesn't, it looks for a way to respond to that message in its prototypes. It finds one in Object.
We can add other prototypes to an object.
code: | Io> D := Object clone do(double := method(*(2)))
==> D_0x8ca27b0:
double = method(...)
type = "D"
Io> 4 appendProto(D)
==> 4
Io> 4 double
==> 8 |
So let's look at something else.
code: | Name := Object clone do(
first := ""
last := ""
fullName := method(first .. " " .. last)
asString := fullName
)
FormalName := Name clone do(
title := ""
fullName := method(title .. " " .. super(fullName))
) |
Now, we can create a name. We just have to clone Name, and give that new object's first and last slots updated values.
code: | bobsName := Name clone do(first = "Bob"; last = "Smith") |
And since bobsName has the Name object as a prototype, and Name has the Object object as a prototype, then it has a println method.
And this naturally prints:
But, what if I want it to print:
Well, I'd need for bobsName to have a title slot. That's easy enough.
code: | bobsName title := "Mr." |
But it's still going to print "Bob Smith" because when this object answers the asString message, it ends up looking for fullName. It finds this in the Name object, but that fullName method doesn't know about title.
The fullName method in the FormalName object does, though. So we just need to make that object a prototype of bobsName.
code: | bobsName prependProto(FormalName) |
|
|
|
|
|
|
Sponsor Sponsor
|
|
|
wtd
|
Posted: Sun Nov 12, 2006 6:11 pm Post subject: (No subject) |
|
|
A little more Io code to contemplate. An RPN calculator.
code: | RPN := List clone do(
doOp := method(op,
if(size >= 2, push(pop perform(op asString, pop)))
)
feedLine := method(line,
line split foreach(item,
try(
push(item fromBase(10))
) catch(Exception,
doOp(item)
)
)
)
run := method(in, out,
while((line := in readLine) isNil not,
feedLine(line)
out write(asString, "\n")
)
)
)
RPN run(File standardInput, File standardOutput) |
|
|
|
|
|
|
wtd
|
Posted: Tue Nov 14, 2006 1:53 pm Post subject: (No subject) |
|
|
code: | Switch := Object clone do(
arg := nil
case := method(
if(call argCount >= 2,
argList := list()
for(i, 0, call argCount - 2, argList append(call evalArgAt(i)))
if(argList detect(v, v == arg),
call evalArgAt(call argCount - 1)
self clone do(prependProto(SatisfiedSwitch)),
self
)
)
)
default := method(call evalArgAt(0))
)
SatisfiedSwitch := Switch clone do(
case := method(self)
default := method(self)
)
Object switch := method(
s := Switch clone
s arg := self
s
)
4 switch case(3,
"Hello" println
) case(2, 4,
"world" println
) default(
"wooble" println
) |
|
|
|
|
|
|
wtd
|
|
|
|
|
|
|