Review

In part 1
we looked at the basic syntactic structure of Ruby. In part 2
we discussed iterators and the fundamentals of Object-Oriented
Programming. Here in part 3 we explore object-orientedness in more detail.

Methods

A method is an action the object knows how to perform on
request. Let's see an example of how a method is invoked for an object:

print "asdfgh".length
^D
6

One can infer from this that a method named `length' of the String
object is called.

From the result it is clear that deciding which method to call is done at
execution time, and that the choice differs depending on the content of the
variable.

I suggest that readers not bother about how the object determines its length
because the process is different for strings and arrays. Fortunately, Ruby
automatically chooses the correct process, so we don't have to worry about it.
This feature in languages supporting object orientedness is called
polymorphism.

It is not necessary for the user to know how the methods are processed, but
one has to know what methods are acceptable to the object. When an object
receives an unknown method, an error is raised. For example: try calling the
"length" method for the object "foo" with value "5".

I had mentioned about a special variable self in Ruby. It is
the object which calls methods. Such callings are used very often and so an
abbreviation is available. That is;

self.method_name(arguments...)

can be omitted then

method_name(arguments...)

causes same effect. Called function is just an abbreviation for method
calling to self.

Classes

The real world consists of objects which can be classified. For example, a
one-year-old child may think `bowwow' on seeing a dog or even a fox. In terms of
object orientedness, `bowwow' can be termed class, and an object
belonging to a class is called instance.

In Ruby, as in other object oriented languages, we first define a class to
determine the behaviour of the object, and then make an instance of the class, a
specific object. So let's define a class in Ruby.

class Dog
def bark
print "Bow wow\n"
end
end
^D

The definition of the class lies between the keywords `class' and
`end'. A `def' in class syntax defines a method of the class.

Now that we have a class named `Dog', let's make an object.

tommy = Dog.new
tommy.bark
^D
Bow wow

This makes a new instance of the class Dog and substitutes it into the
variable tommy. The method `new' of any class makes a new instance. Now the
variable tommy has properties defined in the class Dog, and so he can `bark'.

Inheritence

Ever wondered how others classify objects? One example is how people perceive
a dog. A mathematician may see a dog as an object made up of different numbers
and figures, a physicist may see it as the result of many natural and artificial
forces at work, and my sister (a zoologist) may interpret it as a representative
of the species canine domesticus. To her, a dog is a kind of canine, a
canine is a kind of mammal, and a mammal is always an animal.

Hence we see that the classification of objects takes the form of a
hierarchy, though not in all cases. Let's see what Ruby does with it.

Here the Cat class isn't given any definitions on how to breathe, but it will
inherit that property from the Animal class. In this case, the `bark' feature is
just appended.

It is notable that the properties of the parent class or the super class is
not always inherited. For example, birds fly, but penguins don't. Penguins do
have other properties of birds, though, like laying eggs. This kind of thing can
be represented in Ruby also, and I leave it to the reader as home work.

To make a new class using inheritence from a superclass that holds common
properties, we only need define the differences from the superclass. Some say
this `differential programming' is one of the merits of object oriented
programming.

Redefining Methods

We can observe difference in behaviour of the instances in subclasses when we
redefine the superclass methods. See below:

These are simple examples, but I hope they give you and idea of how
inheritance and redefinition works.

More on Methods

There are some methods which play the role of restricting the way a method is
called. For a function (defined at top level) given below:

def sqr(x)
x * x
end
print sqr(5)
^D
25

When `def' appears outside of class definition, it has effect of adding
this method to the Object class. The Object class is the base class of all other
classes- all classes inherit from the class Object. The means that the method
`sqr' can be used in all other classes.

Now that all classes must be able to call `sqr', let's try to call `sqr' to
`self':

print self.sqr(5)
^D
ERR: private method `sqr' called for (Object)

Calling the function using `self' after the definition of the function gives
the error as shown above. The error message is not intuitive, so what does it
mean?

What is happening is that a method that is defined at the top levelcan can be
called using function style as opposed to method style. See what error message
you get when undefined methods are called.

Since methods are called in a function type style, it works in a fashion
similar to that of C++, while calls are within the class or its subclass.

We can restrict access to methods using `public' or `private' - public
methods can be called by users of the class, while private methods can only be
called by other methods inside this class.

Singleton Method

The behaviour of an instance is determined by the class, but we know that a
particular instance should have special behavior. In most languages, we must
make another class for the instance, while in Ruby we can append methods to a
paticular instance without much fuss.

Another use of modules is called `mixin'. This can be complex so should be
explained in detail.

In some Object-Oriented programming languages, a class can inherit from
more than one superclass; this feature is called multiple-inheritance. Ruby
purposely doesn't have this feature. Instead, we can make it by mixin with the
module.

As said above, the module works like the class; the methods or the constants
of a module cannot be inherited, but instead are appended to other modules or
classes by use of include. So, when one includes the definition of a module,
this adds the property (mixes the property) into the class.

mixin modules appear in the standard library, and by mixing in these modules
to a class whose the `each' method returns each element, the class get the
features: `sort', `find', etc.

The following differences exist between multiple-inheritance and mixin:

The module don't generate instances; it is a guarantee for the abstract
class.

The module keeps the relationship of instance to be a tree.

These differences inhibit complex relationships between classes; simplicity
is a good thing. This is why Ruby doesn't have multiple inheritance. In
languages that have multiple inheritance, situations can occur where classes
have many superclasses and the relationship of instances form a tangled
network... Situations like this are too complex to understand for the brain of
the human being, or at least my brain...

On the other hand, mixins make it simple as just `the collection of
particular properties all we want to add'.

So, even in a language with multiple inheritance, it is recognized that it
is good to extend classes by using mixin rather than developing complicated
inheritance relationships. We advanced this idea in Ruby allowing mixins only
instead of
multiple inheritance.

Procedure Objects

Suppose you are writing a program that does something to process signals.
Those familiar with it will understand the simplicity in sending a procedure as
an argument to a method (here usually arrival of signals).

The built-in method proc generates a procedure object. The
procedure code goes between braces,
and to execute the procedure object
one uses the call method. See below:

obj = proc{print "Hello world\n"}
obj.call
^D
Hello world

C programmers will find procedure objects similar to function pointers.

Conclusion

With this, we come to an end of the series of articles
Part 1, Part 2 and Part 3 with which I have intended to
give readers a basic introduction to programming in Ruby. I have not tried to
present hard core programming in Ruby: this is my final year of Engineering,
and I am busy with my final year project and have been unable to look deeply
into Ruby. But I know that as time permits, I will come up with much more in
Ruby.

Happy Programming...

I am a final year student of Computer Science at Government Engineering
College, Trichur, Kerala, India. Apart from Linux I enjoy learning Physics.