old-www/LDP/LG/issue86/ramankutty.html

398 lines
16 KiB
HTML

<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Programming in Ruby - Part 3 LG #86</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="qubism.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue86/ramankutty.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="tougher.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
<!--endcut ============================================================-->
<TABLE BORDER><TR><TD WIDTH="200">
<A HREF="http://www.linuxgazette.com/">
<IMG ALT="LINUX GAZETTE" SRC="../gx/2002/lglogo_200x41.png"
WIDTH="200" HEIGHT="41" border="0"></A>
<BR CLEAR="all">
<SMALL>...<I>making Linux just a little more fun!</I></SMALL>
</TD><TD WIDTH="380">
<CENTER>
<BIG><BIG><STRONG><FONT COLOR="maroon">Programming in Ruby - Part 3</FONT></STRONG></BIG></BIG>
<BR>
<STRONG>By <A HREF="../authors/ramankutty.html">Hiran Ramankutty</A></STRONG>
</CENTER>
</TD></TR>
</TABLE>
<P>
<!-- END header -->
<H2><B>Review</B></H2>
<P>In <A
href="../issue81/ramankutty.html">part 1</A>
we looked at the basic syntactic structure of Ruby. In <A
href="../issue83/ramankutty.html">part 2</A>
we discussed <B>iterators</B> and the fundamentals of <B>Object-Oriented
Programming</B>. Here in part 3 we explore object-orientedness in more detail.
</P>
<H2><B>Methods</B></H2>
<P>A <B><I>method</I></B> 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: </P>
<P></P><PRE>print "asdfgh".length
^D
6
</PRE>
<P>One can infer from this that a method named `length' of the <B>String
object</B> is called. </P>
<P>Now try this: </P>
<P></P><PRE>foo = "abc"
print foo.length,"\n"
foo = [1, 2]
print foo.length,"\n"
^D
3
2
</PRE>
<P>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. </P>
<P>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
<B><I>polymorphism</I></B>. </P>
<P>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". </P>
<P>I had mentioned about a special variable <B><I>self</I></B> in Ruby. It is
the object which calls methods. Such callings are used very often and so an
abbreviation is available. That is; </P>
<P></P><PRE>self.method_name(arguments...)
</PRE>
<P>can be omitted then </P>
<P></P><PRE>method_name(arguments...)
</PRE>
<P>causes same effect. Called function is just an abbreviation for method
calling to self. </P>
<H2><B>Classes</B></H2>
<P>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 <B><I>class</I></B>, and an object
belonging to a class is called <B><I>instance</I></B>. </P>
<P>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. </P>
<P></P>
<P></P><PRE>class Dog
def bark
print "Bow wow\n"
end
end
^D
</PRE>
<P>The definition of the <B>class</B> lies between the keywords `class' and
`end'. A `def' in class syntax defines a method of the class. </P>
<P>Now that we have a class named `Dog', let's make an object. </P>
<P></P><PRE>tommy = Dog.new
tommy.bark
^D
Bow wow
</PRE>
<P>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'.
</P>
<H2><B>Inheritence</B></H2>
<P>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 <I>canine domesticus</I>. To her, a dog is a kind of canine, a
canine is a kind of mammal, and a mammal is always an animal. </P>
<P>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. </P>
<P></P><PRE>class Animal
def breath
print "inhales and breaths out\n"
end
end
class Cat&lt;Animal
def bark
print "mew\n"
end
end
tama = Cat.new
tama.breath
tama.bark
^D
inhales and breaths out
mew
</PRE>
<P>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. </P>
<P>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. </P>
<P>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. </P>
<H2><B>Redefining Methods</B></H2>
<P>We can observe difference in behaviour of the instances in subclasses when we
redefine the superclass methods. See below: </P<P></P><PRE>class Human
def print_id
print "I'm a human.\n"
end
def train_toll(age)
print "reduced-fare.\n" if age &lt; 12
end
end
Human.new.print_id
class Student1&lt;Human
def print_id
print "I'm a student.\n"
end
end
Student1.new.print_id
class Student2&lt;Human
def print_id
super
print "I'm a student too.\n"
end
end
Student2.new.print_id
^D
I'm a human.
I'm a student.
I'm a human.
I'm a student too.
</PRE>
<P>In the new classes that redefine the superclass methods, the original method
of superclass can be called using `super'. Along with the code above, try this:
</P>
<P></P><PRE>class Student3&lt;Human
def train_toll(age)
super(11) # unconditionally reduced
end
end
Student3.new.train_toll(25)
^D
reduced-fare.
</PRE>
<P>These are simple examples, but I hope they give you and idea of how
inheritance and redefinition works. </P>
<H2><B>More on Methods</B></H2>
<P>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: </P>
<P></P><PRE>def sqr(x)
x * x
end
print sqr(5)
^D
25
</PRE>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.
<P></P>
<P>Now that all classes must be able to call `sqr', let's try to call `sqr' to
`self': </P>
<P></P><PRE>print self.sqr(5)
^D
ERR: private method `sqr' called for (Object)
</PRE>
<P>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? </P>
<P>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. </P>
<P>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. </P>
<P>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. </P>
<P></P><PRE>class Test
def foo
print "foo\n"
end
private foo:
def bar
print "bar -&lt; "
foo
end
end
temp = Test.new
temp.foo
temp.bar
^D
ERR: private method `foo' called for (Test)
bar -&lt; foo
</PRE>
<P>The concept must be clear with the kind of output obtained. </P>
<H2><B>Singleton Method</B></H2>
<P>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. </P>
<P></P><PRE>class SingletonTest
def size
print "25\n"
end
end
t1=SingletonTest.new
t2=SingletonTest.new
def t2.size
print "10\n"
end
t1.size
t2.size
^D
25
10
</PRE>
<P>Here t1 and t2 belong to the same class, though, t2 redefines the `size'
method so it will behave differently. A method of a particular instance is
called <B><I>singleton method</I></B>. </P>
<P>One example where singleton methods are used is in the buttons of a GUI
program, where each button has a different action. We can redefine the action
suitably for each button object. </P>
<H2><B>Modules</B></H2>
<P>Modules in Ruby are very similar to classes, but are used to group related
classes together. There are three major differences between modules and classes:
</P>
<P></P>
<OL>
<LI>Modules have no instance.
<LI>Modules have no subclass.
<LI>Modules are defined by <TT>module ... end</TT>. </LI></OL>
<P>Roughly saying, there are two uses of modules. First, to collect
methods or constants. For example: </P>
<P></P><PRE>print Math::PI,"\n"
print Math.sqrt(2),"\n"
^D
3.141592654
1.414213562
</PRE>
<P>The operator `::' refers to a constants in a module or class. When
we refer directly to the methods or the constants of a method, we use the
`include' method. </P>
<P></P><PRE>include Math
print sqrt(2),"\n"
print PI,"\n"
^D
1.414213562
3.141592654
</PRE>
<P>Another use of modules is called `mixin'. This can be complex so should be
explained in detail. </P>
<P>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. </P>
<P>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. </P>
<P>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. </P>
<P>The following differences exist between multiple-inheritance and mixin:
<UL>
<LI>The module don't generate instances; it is a guarantee for the abstract
class.
<LI>The module keeps the relationship of instance to be a tree. </LI></UL>
<P>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... </P>
<P>On the other hand, mixins make it simple as just `the collection of
particular properties all we want to add'. </P>
<P>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. </P>
<H2><B>Procedure Objects</B></H2>
<P>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). </P>
<P>The built-in method <B><I>proc</I></B> generates a procedure object. The
procedure code goes between braces,
and to execute the procedure object
one uses the <B><I>call</I></B> method. See below: </P>
<P></P><PRE>obj = proc{print "Hello world\n"}
obj.call
^D
Hello world
</PRE>
<P>C programmers will find procedure objects similar to function pointers. </P>
<H2><B>Conclusion</B></H2>With this, we come to an end of the series of articles
<B>Part 1</B>, <B>Part 2</B> and <B>Part 3</B> 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.
<P></P>
<P><B>Happy Programming...</B></P>
<!-- *** BEGIN author bio *** -->
<P>&nbsp;
<P>
<!-- *** BEGIN bio *** -->
<P>
<img ALIGN="LEFT" ALT="[BIO]" SRC="../gx/2002/note.png">
<em>
I am a final year student of Computer Science at Government Engineering
College, Trichur, Kerala, India. Apart from Linux I enjoy learning Physics.
</em>
<br CLEAR="all">
<!-- *** END bio *** -->
<!-- *** END author bio *** -->
<!-- *** BEGIN copyright *** -->
<hr>
<CENTER><SMALL><STRONG>
Copyright &copy; 2003, Hiran Ramankutty.
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
Published in Issue 86 of <i>Linux Gazette</i>, January 2003
</STRONG></SMALL></CENTER>
<!-- *** END copyright *** -->
<HR>
<!--startcut ==========================================================-->
<CENTER>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="qubism.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue86/ramankutty.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="tougher.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->