Showing posts with label trick. Show all posts
Showing posts with label trick. Show all posts

2009-02-20

Fiber

I haven't been here for quite a while. That's simply because I'm not a blogging kind of guy.

Let's have a look at one of the new features in Ruby 1.9.

class Fiber
You can think of a fibre as of a separate thread, but not a thread that is running all the time in the background, but rather one that is responsible for some specialised tasks and is activated only to do some job and return some results.

Also, a fibre is not a thread.

Let's skip to some code:

FILE=__FILE__

require 'fiber'

reader=Fiber::new\
{
File::open(FILE){|f| f.each_line{|l| Fiber.yield(l) unless l.strip.empty?}}
}

puts "Let's get a line: #{reader.resume}"
puts "Let's get anothe line: #{reader.resume}"
puts "And the rest:"
puts reader.resume while reader.alive?


This produces the following output:

Let's get a line: FILE=__FILE__
Let's get anothe line: require 'fiber'
And the rest:
reader=Fiber::new\
{
File::open(FILE){|f| f.each_line{|l| Fiber.yield(l) unless l.strip.empty?}}
}
puts "Let's get a line: #{reader.resume}"
puts "Let's get anothe line: #{reader.resume}"
puts "And the rest:"
puts reader.resume while reader.alive?
#<File:0xb114bc>


So first: let's have a look at the fibre code (I use the word fibre and not fiber because I prefer the British English; the truth is each time I want to use the class
Fiber
I first spell it
Fibre
and must correct later; I'll make an alias one day). The fibre opens the file and calls
Fiber.yield
passing each consecutive nonempty line to it. Think of it like this: it creates a virtual array containing all the elements that you put there, and
Fiber.yield
is putting and element in it. So we have a virtual array containing all the nonempty lines of code from
__FILE__
.

Of course the array does not exist - it is only a way to imagine how the fibre works. This fact saves memory - you don't have to load all the lines to memory before accessing them. Think of how to write this simple program without a fibre (assume that the file you're going to display is like 1G and you cannot simply load it all to memory) - I'm quite sure that using a fibre is one of the best ways to do it.

Now, how do we read from this virtual array? To read an element we call
reader.resume
. Simple, isn't it? Analyse the output to see that it did what we had expected: first it printed the first line, then the second (nonempty) line, and then the rest.

There's only one mysterious thing at the end:
#<File:0xb114bc>
. The explanation is: the virtual array created by a fibre is filled by all calls to
Fiber.yield
, and when the fibre finishes, its final value (the value of the last operation within the fibre block) is also added to the array. In our case, the last (and only) operation is opening the file and
File::open
returns the created file stream, so it was also added to the array. One can like this feature or not, but one has to live with it. So if we didn't want this line of output, we can change the end of the code to this:
puts "And the rest:"
loop\
{
l=reader.resume
break unless reader.alive?
puts l
}

Now it works like it should. More lines of code but oh well.

fiber.resume(*args)
We've seen that if you pass an argument to
Fiber.yield
then it becomes the value of the
fiber.resume
call. This enables you to pass data from the body of the fibre to the outer world. Passing data is also possible in the opposite direction, and is by no means harder. As you might have already guessed: arguments passed to
fiber.resume
are the value of
Fiber.yield
. So if we wanted a writer instead of a reader:
FILE="test.txt"

require 'fiber'

writer=Fiber::new\
{
File::open(FILE,"w")\
{ |f|
loop\
{
l=Fiber.yield
break unless l
f.puts l
}
f.puts "---"
}
}

writer.resume "Line 1"
writer.resume "Line 2"
writer.resume "Line 3"
writer.resume

Why we have to create a
loop
inside the fibre and break from it? Simply because now it's the outer world that decides when to finish the fibre. It signals the fibre to close the file (and add the
"---"
just for our information that the file was closed properly). If we remove the last line of the code (the one that calls the writer with no argument), we'll see that the file won't have
---
added at the end. It will be properly closed due to the finaliser hidden inside
File::open
but it will be closed and released no sooner than the whole program ends so in general it is a good idea to force file close manually.

But wait, there's no line 1 in the file! Yes, it's not there and that's why: the first call to
writer.resume
did not correspond with a call to
Fiber.yield
from within the fibre because at the time of this call the fibre has not yet been started, so it was not waiting on
Fiber.yield
but at the beginning of its block. So the line 1 just activated the fibre, but did not save the line to the file.

What's the solution? First: to get the value of the first call to
writer.resume
you have to add arguments to the fibre block itself. So one of the solutions is like this:
writer=Fiber::new\
{ |l0|
File::open(FILE,"w")\
{ |f|
f.puts(l0)
loop\
{
l=Fiber.yield
break unless l
f.puts l
}
f.puts "---"
}
}


But it doesn't look to nice, nor it is. In our case a best solution might be to use the first call as a special case and pass the file name in it, like this:
require 'fiber'

writer=Fiber::new\
{ |file|
File::open(file,"w")\
{ |f|
loop\
{
l=Fiber.yield
break unless l
f.puts l
}
f.puts "---"
}
}

writer.resume FILE
writer.resume "Line 1"
writer.resume "Line 2"
writer.resume "Line 3"
writer.resume

For most cases I'd use this form.

Of course there are much more uses of
Fiber
, also such kinds that use passing values in both directions simultaneously, not just in one of them, like in the above examples.

Producer - Consumer
Here's one more way of looking at the whole fibre thing: it's sort of the producer - consumer pattern, with a queue of size limited to zero. In this way the element is produced no sooner than it is needed and most of the time there are zero elements waiting on the queue. Only as the fibre is not a thread, there are no synchronisation problems and so on and so on.

I hereby certify the Fiber class for everyday use.

2008-09-01

{block}

Blocks. The most powerful out of the basic features of Ruby.

Block is a way to pass a bit of code into a function, to let the function execute it if it wants to, and as many times as it wants to. You know already some examples like
[1,2,5].each{|e| puts e}
, where the function
each
calls the block three times - once for each element of
self
.

Let's learn how to write a function that takes a block. I'd like to have a method of the class
Array
that converts the array to
Hash
, where the original array elements become keys, and the values are computed inside the block. Example of how it is supposed to work:
[1,5,3].keys_to_hash{|k| k**2}
#=> {1=>1,5=>25,3=>9}

["Ruby","Al2","O3","Cr"].keys_to_hash{|k| k.length}
#=> {"Al2"=>3,"O3"=>2,"Ruby"=>4,"Cr"=>2}
# remember that Hash does not maintain the order of elements
# so they might get reordered when written irb
So, our function definitely takes a block, and executes it once for each element, and collects the return values of the block as values in the hash. The code that does it is like this:
class Array
def keys_to_hash
raise LocalJumpError,"Block not given!" unless block_given?
h={}
each\
{ |e|
h[e]=yield(e)
}
h
end
end
First we raise an exception if the method was called without a block. This line is not obligatory, as the exception would be raised anyway at the moment when we try to execute the block, so I raise it here mostly to show you how to check if a block is given.

Then we create an empty hash, and then for each element of
self
(works like
self.each
) we write an element to the hash, using the current element
e
as the key, and
yield(e)
as the value. As you must have guessed by now, the keyword
yield
is a call to the passed block.

Finally we return the created
h
as the function result. You can check that the function works as expected.

Just one more example:
class Array
def each_consequent(n)
for i in (0..length-n)
yield(*self[i,n])
end
self
end
end

[2,3,5,7,11,13,17,19,23].each_consequent(3)\
{ |a,b,c|
puts "#{a} #{b} #{c}"
}

# output:
2 3 5
3 5 7
5 7 11
7 11 13
11 13 17
13 17 19
17 19 23
I'll explain just the most suspicious part here:
self[i,n]
is an array (subarray of
self
) and we call
yield
with
*
before the array to make the array splash into the three block arguments
|a,b,c|
. This splash operator is not always necessary, but it's nice to include it to make it clear that the arguments get splashed.

If block is an object...
There are in general two ways of passing a block to a next function. Let's define two functions that behave exactly like
each
:
class Array

def my_each1
each{|a| yield(a)}
end

def my_each2(&b)
each(&b)
end

end
The first one makes a trivial block itself - the block is created just to call the original block coming to
my_each1
with the argument. The second one uses the
&
operator to make the block be assigned into the variable
b
. Inside
my_each2
the variable
b
is a
Proc
object. You could call it by hand inside the function, using
b.call(arg)
or for short
b[arg]
, but in our example it is instead passed to
each
, and the operator
&
makes it sort-of-unsplash back into a block. Two other ways to do it (not very elegant, though):
p=Proc::new{|a| yield(a)}; each(&p)
, or another ugly way:
each{|a| b.call(a)}
. I give these example just to touch your brain and make you understand!

If the block is not passed into a function declared with a block parameter, like
my_each2
, the value of
b
is
nil
, and you don't have to call
block_given?
to check it.

...then we can store it
Now another useful trick. If we can receive a block as an object, or wrap it into a new
Proc
, then it's an object, and can be stored in a variable. Look:
class K

def store_block(&b)
@b=b
end

def call_block(*args)
@b.call(*args)
end

end

k=K::new
k.store_block{|a,b| puts "#{a}::#{b}"} # no output to the console
k.call_block("Al2O3","Cr") # output: Al2O3::Cr
k.call_block("Hi","there") # output: Hi::there
So, we saved the passed block, and called it later. Note one very useful trick: if we receive the arguments as
*args
and pass them on as
*args
as well, then any set of arguments, no matter how many of them you pass to
call_block
, will get forwarded to the block call. (Of course now calling
k.call_block(1,2,3)
will print just
"1::2"
because our block takes two arguments, which means it ignores the third one; but the argument gets lost in the block, and not in
call_block
).

This block saving is not useless. You can for example call a method that saves a block, and executes it later as a callback to an event that happens inside the object. This is a very useful behaviour.

Passing more blocks
Unfortunatelly, Ruby doesn't support passing more blocks to a function. You can have only one parameter with
&
, and there is only one
yield
too. But Ruby does allow passing multiple regular arguments, so what's the problem? Let's write a function that sort of takes two blocks, and calls one of them with the result returned by the call to the other with the argument 5, or opposite:
def random_caller(b1,b2)
raise ArgumentError,"Arguments must be Procs"\
unless b1.is_a? Proc and b2.is_a? Proc
if rand(2).zero?
b1.call(b2.call(5))
else
b2.call(b1.call(5))
end
end

q=lambda\
{
random_caller(lambda{|x| x+2},lambda{|x| x**2})
}
q[] #=> 27
q[] #=> 27
q[] #=> 49
q[] #=> 27
q[] #=> 27
First we check if what we really got are procs. Then we randomly call one of them with
5
and the other with the result of the first one, or the opposite, and return the result.

Now the call. The structure
lambda{|arg| exp}
is more or less the same as
Proc::new{|arg| exp}
and
proc{|arg| exp}
. So
random_caller(lambda{|x| x+2},lambda{|x| x**2})
is a call to our function, and we can expect the result of the call to be either
(5+2)**2
which is
49
, or
(5**2)+2
which is
27
.

Now we must call our function multiple times. We could do it like this:
5.times{random_caller(lambda{|x| x+2},lambda{|x| x**2})}
But, as a part of this tutorial, I made the call to the function into another proc, and stored it in
q
. As you see, you don't even have to pass a block to a function to store it somewhere. You can create a proc just like that, and store it in a local variable, and then call it using
q[]
or
q.call
.

Scope
The scope visible to a block is its declaration scope. What is very interesting, even when the scope is no longer accessible, because the control left the function, it still exists if a lambda was declared there and can use it. This example illustrates the complicated words I just said:
def create_blocks
x=nil
getter=lambda{x}
setter=lambda{|v| x=v}
[setter,getter]
end

s,g=*create_blocks
s[6] # or s.call(6)
g #=> 6
s[:R]
g #=> :R
The scope from inside
create_blocks
is not lost, even though the control left the method and will never return. The variable
x
is still accessible by the lambdas declared in the scope.

Other sources
Here are some link to learn more about gotchas in Ruby's blocks.
Ruby blocks gotchas
Proc vs lambda
Wikipedia - Closure (in many other languages the Ruby clock thing is called closure, or probably more like the closures are called blocks in Ruby)
Wikipedia Smalltalk (this blocks are pretty modern and fresh programming things, aren't they? well, they're not; have a look at Smalltalk (1980))

2008-08-24

Object **arr;

What? What do these asterisks do? We're having Ruby here, and the whole old pointers things from C++ are gone, aren't they?

Well, they are not, sorry. Remember one thing, please. This pointers thing is not a part of C++ or any other particular language. Pointers are how computers work. Each (reasonable) programming language either has pointers, or is inefficient. Ruby has them too. The difference is that in Ruby we don't use asterisks to denote we're using them.

What's "wrong"

Have a look at the example that proves we have pointers in Ruby:
a=[2,3,5,7]   #=> [2, 3, 5, 7]
b=a #=> [2, 3, 5, 7]
a<<11 #=> [2, 3, 5, 7, 11]
a #=> [2, 3, 5, 7, 11]
b #=> [2, 3, 5, 7, 11]
So, as you see,
a
and
b
are just pointers. And when we make the substitution in the second line, we just make them point to the same object in memory (array, in our example), so when we modify the object using an in place changing method (like
reverse!
,
clear
and others), the change will be also visible through the other variable.

We observe exactly the same behaviour when we use a string instead of an array:
a="abc"       #=> "abc"
b=a #=> "abc"
a<<"x" #=> "abcx"
a #=> "abcx"
b #=> "abcx"
Note that if you use
+=
instead of
<<
, a new instance of the string with the
"x"
appended is created and assigned to
a
, so if you want to make a string buffer and append to it some lines, it's probably better to use
<<
, because it does not create another object.

So, what if we would like to have an independent copy of a given array or a string? Ruby comes with a function
dup
that makes a copy of an object. (In fact there's also a function
clone
that behaves similarily, for today let's assume the functions do exactly the same (they don't), and let's use
dup
.) Change the line
b=a
to
b=a.dup
in both examples above and you will see it works like expected - modifying
a
does not modify
b
and vice versa.

Happy? So, is that all for today? Not quite. Have a look:
a=["a","b"]
b=a.dup
a<<"c"
b #=> ["a", "b"] # as expected
a[0]<<"x"
a             #=> ["ax", "b", "c"]
b #=> ["ax", "b"] # oops!
What happened? Well, now
b
is a copy of
a
, which means they are two separate arrays, so when we add
"c"
to one of them, the other does not get modified, we already know that. But in Ruby everything is an
Object
, so the elements of the arrays are objects too, and, what worse, they are the same objects. When we did
b=a.dup
, we created a separate array, but the elements of the array are pointers to the same strings as the elements of the original array. Our copy is not deep, we separated the top-level objects but not the elements of the array. So when we modified in place one of the elements, it got modified also in the other array, even though the arrays are separate objects.

Another way to check what happens:
x=Object::new       #=> #<Object:0x2d8ce10>
x.dup #=> #<Object:0x2d91dfc>
[x] #=> [#<Object:0x2d8ce10>]
[x].dup #=> [#<Object:0x2d8ce10>]
As you see,
dup
on an object makes a new object (the addresses differ), but
dup
on an array makes a new array but does not make a copy of the elements - it just makes a new array with its elements pointing to the original objects.

How to "fix" it
OK, so let's change the behaviour of
dup
for
Array
so that it makes a deep copy calling
dup
recursively on all its elements. Good idea? Yes, but NO NO NO!

Never do such a thing as changing the behaviour of a standard function! Someone can depend on how it works now, so you cannot change it! Remember well this lesson! Even if you think it's broken, don't fix it in this way!

Sorry for shouting, but it is important. Let's define a new function with the functionality we've just described. Here's how we do it:
class Object
def deep_dup
dup
end
end

class Array
def deep_dup
map{|e| e.deep_dup}
end
end

class Hash
def deep_dup
h={}
each{|k,v| h[k.deep_dup]=v.deep_dup}
h
end
end
First we define
deep_dup
for "normal" object as a simple copy, as they do not need any special treatment. Then we redefine (override) the function for
Array
and also for
Hash
, as there's exactly the same case with hashes as with arrays. You can check that after changing
dup
to
deep_dup
in the examples above, everything will work as expected.

Of course there are also other classes like
Set
(available after
require 'set'
) that might need overriding
deep_dup
for them to work.

So why use dup?
Now another lesson: why at all use this strange-working
dup
if we have such a nice
deep_dup
? Well, the answer is simple: as
deep_dup
copies everything, it might use much more memory (and time) than
dup
. That's why I said that if a language doesn't have pointers (that is, if a normal substitution works just like our
deep_dup
), it is inefficient. Because the solution is not to stop using
dup
. The solution is to use it carefully and wisely. And to remember, that there are pointers under the nice skin of Ruby.

Other methods
If we need a deep copy, the approach described above is probably the best one, but not the only one. One of the most secure methods to create a complete deep copy of an object is to serialise it to a "soul-less" string and deserialise it back. Then we can be absolutely sure that no part of the new object will be a part of the original one, as deserialisation for sure creates the object from scratch.

Ruby provides two easy serialisation methods:
YAML
and
Marshal
.
require 'yaml'

class Object

def m_dup
Marshal.load(Marshal.dump(self))
end

def y_dup
YAML.load(YAML.dump(self))
end

end
Both
YAML
and
Marshal
have a method
dump
that returns a string representation of the object passed (you can see how the strings look like by calling
dump
on various objects in irb), and the method
load
that does the reverse.

Differences:
- as you can see,
Marshal
's string is shorter so probably it's better and more efficient.
-
YAML
does not always work. I don't know why this is happening, but some complicated structures with sets, arrays, strings and hashes fail to load from the dumped string.

Both methods are most probably worse (slower) than our
deep_dup
, because they need to parse the string.

Last problem - self-references
There's one point, however, where the serialisation method works, and our
deep_dup
fails. It is when an array is an element of itself:
a=[]
a<<a
a #=> [[...]] # the three dots denote a self-reference
a.deep_dup
SystemStackError: stack level too deep
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
... 15577 levels...
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):87:in `deep_dup'
from (irb):87:in `map'
from (irb):87:in `deep_dup'
from (irb):115
from (null):0

Aww, a failure, because duplicating
a
needs duplicating
a
first, and so on. That's why our method is not so perfect, and will fail also on examples like this:
a=[1,2,{:a=>4}]
a[2][:b]=a
a #=> [1, 2, {:a=>4, :b=>[...]}]
It can be fixed and handled just as it is handled in serialisation (it works without problems with such objects), and also in
inspect
(if it wasn't, you'd have an infinite output after creating such an object in irb), but I'll leave this as an exercise for the reader.

One more method
This last method is so bad that you should never use it, I just mention it to give you another knol to think about.
class Object
def i_dup
eval(inspect)
end
end
It calls the method
inspect
to create a human-readable representation of the object, just like irb does after each command, and then passes the string to
eval
that simply executes the string.

You should know by yourself why this method is bad, but just to make it clear:
- it only works for objects "made of"
Array
,
Hash
,
Numeric
,
String
,
Range
and
Symbol
instances (maybe some more I forgot about now), it won't work for
Object::new
,
- it doesn't handle self-reference (it fails when it sees the three dots).

That's all for today, I hope you learnt something new.

2008-08-17

Lazy evaluation

Let's make an array of all Fibonacci numbers. All of them? Yes, all of them!

Of course it's impossible, we would have to spend infinite time computing them and use infinite memory to store them. But we can trick users of our array into thinking it does have all the numbers precomputed in it. We will use lazy evaluation.

How it works? Well, our array will not really be an Array from which we can read fields at random. It will be an object, and each time user wants to get some number from it, we will peek into the user's request, and compute the number, if not already computed. This simple concept is the definition of lazy evaluation (opposed to eager evaluation, which is precomputing values before they are needed).

The object that will look like the array will be a module. We don't want to create a class, because we wouldn't want to instantiate it. It will work just like this:
Fi[10]
will yield
55
, for instance (we assume
Fi[0]==0 and Fi[1]==1
).

Let's start with the code, as usually.
module Fi

class << self

def initialize
@fi=[0,1]
end

def [](n)
raise ArgumentError,"Incorrect index!" unless n.is_a? Integer and n>=0
get(n)
end

def each
i=0
loop\
{
yield(get(i))
i+=1
}
end

private

def get(n)
want(n)
@fi[n]
end

def want(n)
until @fi[n]
@fi<<@fi[-1]+@fi[-2]
end
end

end

initialize

end
Note that this is not a good implementation, a good implementation would use Matrix form to compute them much faster, but we're talking about laziness here, so let's leave the good implementation to the eager folks (well, if you do it, it will probably increase your Ruby skills, so try, if you dare). Also what I want to demonstrate doesn't get lost between the matrices in this simple implementation, so let's stick with it for now.

So, we declared a
module
, and then there's this funny
class << self
in it. Well, for now, just remember that that's the way (one of the ways) to turn a module into sort of a singleton class - a structure that has functions and maintains its state, but cannot be freely instantiated. Also note how it is initialized: we defined initializer inside the class, but we have to call in explicitely after the class definition in the module (in fact we could call this function anything else).

After this introduction, just remember that the module can be treated like an object. We define this object's most important method:
[]
(defining a method
[](params)
enables us to use the object as an Array - one more teaspoon of the syntactic sugar).

After validating the argument, we call the function
get
, which calls
want
and after that reads the value from the field
@fi
, which is the underlying real array of Fibonacci numbers. The function
want
simply ensures that there are at least
n
numbers counted by counting consecutive numbers until the one we want is inserted into the array (
@fi[-1]
is of course the last element of the array - another teaspoon, very handy).

Time to test our module:
irb(main):042:0> Fi[10]
=> 55
Exactly what we wanted! Note that when we ask for
Fi[100000]
, the console hungs for a moment before giving us the result, but when we want the some number again, it works immediately (if you see a delay, it's caused exclusively by the time needed to print the output, to see the real time the computation takes, try
Fi[100000];nil
to suppress the output).

Now get back to our code and have a look at the
each
method. Arrays have methd
each
that calls the passed block once for each element. Our object is a bit like Array so why not add this option? The only problem is, of course, that the function will never finish, unless user breaks it like this:
Fi.each\
{ |f|
puts f
break if f>100000
}
In fact the
break
breaks the loop inside the method, and lets it finish.

Again, our
each
is implemented badly. It should precompute some number of numbers ahead to reduce the number of calls to
get
. Well, calling
get
and not
[]
is already an optimisation, because thanks to this we don't validate the argument each time inside
each
.

We could also implement
each_with_index
and others, also
map
could be implemented, but it would have to behave differently from what it does for Arrays, because if we
break
inside
map
of an Array object, it returns
nil
, and our
map
would have to return the already computed part of the array. But definitely the most important change would be to introduce the matrix form to the calculations, so that if we ask for just one number, not all previous numbers would have to be calculated. I leave it as an exercise for the reader.

2008-08-13

Non-standard standard methods

Hello there again. Today we're discussing one useless and potentially distructive thing. But it's gonna be very educational.

The mad machine
There's a story about two engineers: Trurl and Klapaucius. They built once a machine that was absolutely sure that two plus two is seven. They had a lots of problems as the machine was chasing them to prove it was right, so be aware today!

When you open irb and write
2+2
, do you suppose the stupid machine could answer
7
? Well, let's imagine I'm Trurl and you're Klapaucius. Copy the following into your irb (you can copy all lines at a go):
class Fixnum
alias q +
def +(b)
if self==2 and b==2
7
else
q(b)
end
end
end
Try now:
2+2
Oh no, RUN, the machine is MAD! ... ahh no, sorry. We just changed the way that numbers get added to each other. Let's analyse what we just did here. First, we said
class Fixnum
. That would create a class, if only the class had not already existed. But if it does exist, this instruction does not do anything, it just signalises that we're going to add or change something inside this class. Note here the difference in behaviour between "redeclaring" classes and methods: when you declare again the same method, it destroys the old one (I explained this in the previous post), but if we "redeclare" a class, we just enter the inside of the class. Opening a class in this way is never destructive.

OK, what now? Let's skip for a moment the second line. We want to redeclare the method
+
. We do it here:
def +(b)
. As you see, we can define operators just like any other methods. This also means that writing
10.+(5)
in irb will work just like
10+5
- they both simply call a method
+
of the object
10
with the argument
5
.

So what we do inside this newly defined addition? We check, if both the object whose method it is (
self
) (that is: the first operand), and the second operand
b
are 2, we return 7. And if not, we're calling a method
q
(it's a one-argument method, wait a moment) (it could be written:
self.q(b)
, because it is method of the current object, that is the first operand).

So what's that method
q
? This method is defined in this line
alias q +
, and this line means: define method
q
that does exactly the same as the method
+
. Now note it well, that the
alias
line is above the
def
line, so the new method
q
is exactly the same as the old method
+
, not the new one that we just define below! So now we've covered the method
+
with the new one, so the old one is not accessible under its name
+
, but, what a lucky coincidence - we've made a "copy" of the old method
+
by giving it a new name
q
. So now, from within the new adding method, we can call the old one under its new name, and in this way we are able to add the two numbers if they are not two and two. That's how we maintain the old functionality while adding new one under the same name (the same method name, namely).

What are you doing, irb?
Let's try a variation now. (Close the console and open a new one to get rid of the mad machine.)
class Fixnum
alias q +
def +(b)
puts "#{self}+#{b}"
q(b)
end
end
Note that we used a very useful notation here: if you type
"a String #{with_something_inside} encosed like this,"
the thing in the braces gets evaluated and the result is inserted into the string.

Now let's type something trivial in the console now. I typed this:
"Al2O3::Cr"
:
irb(main):009:0> "Al2O3::Cr"
8+1
85+1
0+1
86+1
1+1
86+1
1+1
87+1
2+1
88+1
3+1
89+1
4+1
90+1
5+1
91+1
6+1
92+1
7+1
93+1
8+1
94+1
9+1
95+1
10+1
96+1
9+1
=> "Al2O3::Cr"
irb(main):010:0>
Wow, now we know what additions were performed by irb! Usually you cannot tell what these additions really do, but the last one is probably the line number incrementation in irb. Other of them are responsible for parsing the string and displaying it.

inspect
One more trick. You must have noticed that the objects can be displayed in two ways: as an internal representation, or as a displayable thing:
irb(main):001:0> obj="a \"string\"\nsecond line"
=> "a \"string\"\nsecond line"
irb(main):002:0> puts obj
a "string"
second line
As you see, when we
puts
a string, the result is something else than when we just use it, and irb shows us how it looks after the
=>
sign. The same is true for other types than String:
irb(main):003:0> obj=["a",5,:x]
=> ["a", 5, :x]
irb(main):004:0> puts obj
a
5
x
=> nil
irb(main):005:0> obj.to_s
=> "a5x"
Even one more representation here, obtained by calling
to_s
. So, how does it work?

The method
to_s
for a String returns itself, and for Array returns concatenation of elements'
to_s
's ( Note that this is going to change in Ruby 1.9!). But when irb wants to show us a result of an operation, it doesn't use
to_s
. It uses the method
inspect
. Try it:
[1,"a"].inspect
returns something that looks like
"[1, \"a\"]"
in irb, and what is really
[1, "a"]
, that is exactly how irb presents this value after the
=>
sign. You can emulate irb's behaviour like this:
puts obj.inspect
or easier
p obj
, but you are not very likely to use it in real programs, save for debugging purposes.

Let's do a little change now:
class String
alias inspect_old inspect
def inspect
inspect_old.gsub(/(^")|("$)/,"*")
end
end
We replace the method
inspect
with a new one, that calls the old one, and then replaces the quotation marks (
"
) at the beginning and the end of the result of the inspection with asterisks. Now just try it out:
irb(main):019:0> "Susan"
=> *Susan*
Do you like it?