398 lines
16 KiB
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<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 < 12
|
|
end
|
|
end
|
|
Human.new.print_id
|
|
class Student1<Human
|
|
def print_id
|
|
print "I'm a student.\n"
|
|
end
|
|
end
|
|
Student1.new.print_id
|
|
class Student2<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<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 -< "
|
|
foo
|
|
end
|
|
end
|
|
temp = Test.new
|
|
temp.foo
|
|
temp.bar
|
|
^D
|
|
ERR: private method `foo' called for (Test)
|
|
bar -< 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>
|
|
<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 © 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 ============================================================-->
|