SEARCH
NEW RPMS
DIRECTORIES
ABOUT
FAQ
VARIOUS
BLOG
DONATE


YUM REPOSITORY

 
 

MAN page from openSUSE Tumbleweed perl-HTML-Tree-5.07-1.4.noarch.rpm

HTML::Tree::AboutObjects

Section: User Contributed Perl Documentation (3)
Updated: 2017-09-01
Index 

NAME

HTML::Tree::AboutObjects -- article: "User's View of Object-Oriented Modules" 

SYNOPSIS

  # This an article, not a module.
 

DESCRIPTION

The following article by Sean M. Burke first appeared in The PerlJournal #17 and is copyright 2000 The Perl Journal. It appearscourtesy of Jon Orwant and The Perl Journal. This document may bedistributed under the same terms as Perl itself. 

A User's View of Object-Oriented Modules

-- Sean M. Burke

The first time that most Perl programmers run into object-orientedprogramming when they need to use a module whose interface isobject-oriented. This is often a mystifying experience, since talk of``methods'' and ``constructors'' is unintelligible to programmers whothought that functions and variables was all there was to worry about.

Articles and books that explain object-oriented programming (OOP), do soin terms of how to program that way. That's understandable, and if youlearn to write object-oriented code of your own, you'd find it easy touse object-oriented code that others write. But this approach is thelong way around for people whose immediate goal is just to useexisting object-oriented modules, but who don't yet want to know all thegory details of having to write such modules for themselves.

This article is for those programmers --- programmers who want to knowabout objects from the perspective of using object-oriented modules. 

Modules and Their Functional Interfaces

Modules are the main way that Perl provides for bundling up code forlater use by yourself or others. As I'm sure you can't help noticingfrom readingThe Perl Journal, CPAN (the Comprehensive Perl ArchiveNetwork) is the repository for modules (or groups of modules) thatothers have written, to do anything from composing music to accessingWeb pages. A good deal of those modules even come with everyinstallation of Perl.

One module that you may have used before, and which is fairly typical inits interface, is Text::Wrap. It comes with Perl, so you don't evenneed to install it from CPAN. You use it in a program of yours, byhaving your program code say early on:

  use Text::Wrap;

and after that, you can access a function called "wrap", which insertsline-breaks in text that you feed it, so that the text will be wrapped toseventy-two (or however many) columns.

The way this "use Text::Wrap" business works is that the moduleText::Wrap exists as a file ``Text/Wrap.pm'' somewhere in one of yourlibrary directories. That file contains Perl code...

Footnote: And mixed in with the Perl code, there's documentation, whichis what you read with ``perldoc Text::Wrap''. The perldoc program simplyignores the code and formats the documentation text, whereas ``useText::Wrap'' loads and runs the code while ignoring the documentation.

...which, among other things, defines a function called "Text::Wrap::wrap",and then "exports" that function, which means that when you say "wrap"after having said ``use Text::Wrap'', you'll be actually calling the"Text::Wrap::wrap" function. Some modules don't export theirfunctions, so you have to call them by their full name, like"Text::Wrap::wrap(...parameters...)".

Regardless of whether the typical module exports the functions itprovides, a module is basically just a container for chunks of code thatdo useful things. The way the module allows for you to interact withit, is its interface. And when, like with Text::Wrap, its interfaceconsists of functions, the module is said to have a functionalinterface.

Footnote: the term ``function'' (and therefore "functional") hasvarious senses. I'm using the term here in its broadest sense, torefer to routines --- bits of code that are called by some name andwhich take parameters and return some value.

Using modules with functional interfaces is straightforward --- insteadof defining your own ``wrap'' function with "sub wrap { ... }", youentrust ``use Text::Wrap'' to do that for you, along with whatever otherfunctions its defines and exports, according to the module'sdocumentation. Without too much bother, you can even write your ownmodules to contain your frequently used functions; I suggest having a look atthe "perlmod" man page for more leads on doing this. 

Modules with Object-Oriented Interfaces

So suppose that one day you want to write a program that will automatethe process of "ftp"ing a bunch of files from one server down to yourlocal machine, and then off to another server.

A quick browse through search.cpan.org turns up the module ``Net::FTP'',which you can download and install it using normal installationinstructions (unless your sysadmin has already installed it, as manyhave).

Like Text::Wrap or any other module with a familiarly functionalinterface, you start off using Net::FTP in your program by saying:

  use Net::FTP;

However, that's where the similarity ends. The first hint ofdifference is that the documentation for Net::FTP refers to it as aclass. A class is a kind of module, but one that has anobject-oriented interface.

Whereas modules like Text::Wrapprovide bits of useful code as functions, to be called like"function(...parameters...)" or like"PackageName::function(...parameters...)", Net::FTP and other moduleswith object-oriented interfaces provide methods. Methods are sort oflike functions in that they have a name and parameters; but methodslook different, and are different, because you have to call them with asyntax that has a class name or an object as a special argument. I'llexplain the syntax for method calls, and then later explain what theyall mean.

Some methods are meant to be called as class methods, with the classname (same as the module name) as a special argument. Class methodslook like this:

  ClassName->methodname(parameter1, parameter2, ...)  ClassName->methodname()   # if no parameters  ClassName->methodname     # same as above

which you will sometimes see written:

  methodname ClassName (parameter1, parameter2, ...)  methodname ClassName      # if no parameters

Basically all class methods are for making new objects, and methods thatmake objects are called "constructors`` (and the process of making themis called ''constructing`` or ''instantiating``). Constructor methodstypically have the name ''new``, or something including ''new``(''new_from_file``, etc.); but they can conceivably be namedanything --- DBI's constructor method is named ''connect", for example.

The object that a constructor method returns istypically captured in a scalar variable:

  $object = ClassName->new(param1, param2...);

Once you have an object (more later on exactly what that is), you canuse the other kind of method call syntax, the syntax for object methodcalls. Calling object methods is just like class methods, exceptthat instead of the ClassName as the special argument,you use an expression that yeilds an ``object''. Usually this isjust a scalar variable that you earlier captured theoutput of the constructor in. Object method calls look like this:

  $object->methodname(parameter1, parameter2, ...);  $object->methodname()   # if no parameters  $object->methodname     # same as above

which is occasionally written as:

  methodname $object (parameter1, parameter2, ...)  methodname $object      # if no parameters

Examples of method calls are:

  my $session1 = Net::FTP->new("ftp.myhost.com");    # Calls a class method "new", from class Net::FTP,    #  with the single parameter "ftp.myhost.com",    #  and saves the return value (which is, as usual,    #  an object), in $session1.    # Could also be written:    #  new Net::FTP('ftp.myhost.com')  $session1->login("sburke","aoeuaoeu")    || die "failed to login!\n";     # calling the object method "login"  print "Dir:\n", $session1->dir(), "\n";  $session1->quit;    # same as $session1->quit()  print "Done\n";  exit;

Incidentally, I suggest always using the syntaxes with parentheses and``->'' in them,

Footnote: the character-pair ``->'' is supposed to look like anarrow, not ``negative greater-than''!

and avoiding the syntaxes that start out ``methodname $object'' or``methodname ModuleName''. When everything's going right, they all meanthe same thing as the ``->'' variants, but the syntax with ``->'' is morevisually distinct from function calls, as well as being immune to somekinds of rare but puzzling ambiguities that can arise when you're tryingto call methods that have the same name as subroutines you've defined.

But, syntactic alternatives aside, all this talk of constructing objectsand object methods begs the question --- what is an object? There areseveral angles to this question that the rest of this article willanswer in turn: what can you do with objects? what's in an object?what's an object value? and why do some modules use objects at all? 

What Can You Do with Objects?

You've seen that you can make objects, and call object methods withthem. But what are object methods for? The answer depends on the class:

A Net::FTP object represents a session between your computer and an FTPserver. So the methods you call on a Net::FTP object are for doingwhatever you'd need to do across an FTP connection. You make thesession and log in:

  my $session = Net::FTP->new('ftp.aol.com');  die "Couldn't connect!" unless defined $session;    # The class method call to "new" will return    # the new object if it goes OK, otherwise it    # will return undef.      $session->login('sburke', 'p@ssw3rD')   || die "Did I change my password again?";    # The object method "login" will give a true    # return value if actually logs in, otherwise    # it'll return false.

You can use the session object to change directory on that session:

  $session->cwd("/home/sburke/public_html")     || die "Hey, that was REALLY supposed to work!";   # if the cwd fails, it'll return false

...get files from the machine at the other end of the session...

  foreach my $f ('log_report_ua.txt', 'log_report_dom.txt',                 'log_report_browsers.txt')  {    $session->get($f) || warn "Getting $f failed!"  };

...and plenty else, ending finally with closing the connection:

  $session->quit();

In short, object methods are for doing things related to (or with)whatever the object represents. For FTP sessions, it's about sendingcommands to the server at the other end of the connection, and that'sabout it --- there, methods are for doing something to the world outsidethe object, and the objects is just something that specifies what bitof the world (well, what FTP session) to act upon.

With most other classes, however, the object itself stores some kind ofinformation, and it typically makes no sense to do things with such anobject without considering the data that's in the object. 

What's in an Object?

An object is (with rare exceptions) a data structure containing abunch of attributes, each of which has a value, as well as a namethat you use when youread or set the attribute's value. Some of the object's attributes areprivate, meaning you'll never see them documented because they're notfor you to read or write; but most of the object's documented attributesare at least readable, and usually writeable, by you. Net::FTP objectsare a bit thin on attributes, so we'll use objects from the classBusiness::US_Amort for this example. Business::US_Amort is a verysimple class (available from CPAN) that I wrote for making calculationsto do with loans (specifically, amortization, using US-stylealgorithms).

An object of the class Business::US_Amort represents a loan withparticular parameters, i.e., attributes. The most basic attributes of a``loan object'' are its interest rate, its principal (how much money it'sfor), and it's term (how long it'll take to repay). You need to setthese attributes before anything else can be done with the object. Theway to get at those attributes for loan objects is just like theway to get at attributes for any class's objects: through accessors.An accessor is simply any method that accesses (whether reading orwriting, AKA getting or putting) some attribute in the given object.Moreover, accessors are the only way that you can changean object's attributes. (If a module's documentation wants you toknow about any other way, it'll tell you.)

Usually, for simplicity's sake, an accessor is named after the attributeit reads or writes. With Business::US_Amort objects, the accessors youneed to use first are "principal", "interest_rate", and "term".Then, with at least those attributes set, you can call the "run" methodto figure out several things about the loan. Then you can call variousaccessors, like "total_paid_toward_interest", to read the results:

  use Business::US_Amort;  my $loan = Business::US_Amort->new;  # Set the necessary attributes:  $loan->principal(123654);  $loan->interest_rate(9.25);  $loan->term(20); # twenty years  # NOW we know enough to calculate:  $loan->run;    # And see what came of that:  print    "Total paid toward interest: A WHOPPING ",    $loan->total_paid_interest, "!!\n";

This illustrates a convention that's common with accessors: calling theaccessor with no arguments (as with $loan->total_paid_interest) usuallymeans to read the value of that attribute, but providing a value (aswith $loan->term(20)) means you want that attribute to be set to thatvalue. This stands to reason: why would you be providing a value, ifnot to set the attribute to that value?

Although a loan's term, principal, and interest rates are all singlenumeric values, an objects values can any kind of scalar, or an array,or even a hash. Moreover, an attribute's value(s) can be objectsthemselves. For example, consider MIDI files (as I wrote about inTPJ#13): a MIDI file usually consists of several tracks. A MIDI file iscomplex enough to merit being an object with attributes like its overalltempo, the file-format variant it's in, and the list of instrumenttracks in the file. But tracks themselves are complex enough to beobjects too, with attributes like their track-type, a list of MIDIcommands if they're a MIDI track, or raw data if they're not. So Iended up writing the MIDI modules so that the ``tracks'' attribute of aMIDI::Opus object is an array of objects from the class MIDI::Track.This may seem like a runaround --- you ask what's in one object, and getanother object, or several! But in this case, it exactly reflectswhat the module is for --- MIDI files contain MIDI tracks, which thencontain data. 

What is an Object Value?

When you call a constructor like Net::FTP->new(hostname), you getback an object value, a value you can later use, in combination with amethod name, to call object methods.

Now, so far we've been pretending, in the above examples, that thevariables $session or $loan are the objects you're dealing with.This idea is innocuous up to a point, but it's really a misconceptionthat will, at best, limit you in what you know how to do. The realityis not that the variables $session or $query are objects; it's a littlemore indirect --- they hold values that symbolize objects. The kind ofvalue that $session or $query hold is what I'm calling an object value.

To understand what kind of value this is, first think about the otherkinds of scalar values you know about: The first two scalar values youprobably ever ran into in Perl are numbers and strings, which youlearned (or just assumed) will usually turn into each other on demand;that is, the three-character string ``2.5'' can become the quantity twoand a half, and vice versa. Then, especially if you started using"perl -w" early on, you learned about the undefined value, which canturn into 0 if you treat it as a number, or the empty-string if youtreat it as a string.

Footnote: You may also have been learning about references, in whichcase you're ready to hear that object values are just a kind ofreference, except that they reflect the class that created thing they pointto, instead of merely being a plain old array reference, hash reference,etc. If this makes makes sense to you, and you want to know moreabout how objects are implemented in Perl, have a look at the"perltoot" man page.

And now you're learning about object values. An object value is avalue that points to a data structure somewhere in memory, which iswhere all the attributes for this object are stored. That datastructure as a whole belongs to a class (probably the one you named inthe constructor method, like ClassName->new), so that the object valuecan be used as part of object method calls.

If you want to actually see what an object value is, you might tryjust saying ``print $object''. That'll get you something like this:

  Net::FTP=GLOB(0x20154240)

or

  Business::US_Amort=HASH(0x15424020)

That's not very helpful if you wanted to really get at the object'sinsides, but that's because the object value is only a symbol for theobject. This may all sound very abstruse and metaphysical, so areal-world allegory might be very helpful:

You get an advertisement in the mail saying that you have been(im)personally selected to have the rare privilege of applying for acredit card. For whatever reason, this offer sounds good to you, so youfill out the form and mail it back to the credit card company. Theygleefully approve the application and create your account, and send youa card with a number on it.

Now, you can do things with the number on that card --- clerks at storescan ring up things you want to buy, and charge your account by keying inthe number on the card. You can pay for things you order online bypunching in the card number as part of your online order. You can payoff part of the account by sending the credit card people some of yourmoney (well, a check) with some note (usually the pre-printed slip)that has the card number for the account you want to pay toward. And youshould be able to call the credit card company's computer and ask itthings about the card, like its balance, its credit limit, its APR, andmaybe an itemization of recent purchases ad payments.

Now, what you're really doing is manipulating a credit cardaccount, a completely abstract entity with some data attached to it(balance, APR, etc). But for ease of access, you have a credit cardnumber that is a symbol for that account. Now, that symbol is just abunch of digits, and the number is effectively meaningless and uselessin and of itself --- but in the appropriate context, it's understood tomean the credit card account you're accessing.

This is exactly the relationship between objects and object values, andfrom this analogy, several facts about object values are a bit moreexplicable:

* An object value does nothing in and of itself, but it's useful whenyou use it in the context of an $object->method call, the same way thata card number is useful in the context of some operation dealing with acard account.

Moreover, several copies of the same object value all refer to the sameobject, the same way that making several copies of your card numberwon't change the fact that they all still refer to the same singleaccount (this is true whether you're ``copying'' the number by justwriting it down on different slips of paper, or whether you go to thetrouble of forging exact replicas of your own plastic credit card). That'swhy this:

  $x = Net::FTP->new("ftp.aol.com");  $x->login("sburke", "aoeuaoeu");

does the same thing as this:

  $x = Net::FTP->new("ftp.aol.com");  $y = $x;  $z = $y;  $z->login("sburke", "aoeuaoeu");

That is, $z and $y and $x are three different slots for values,but what's in those slots are all object values pointing to the sameobject --- you don't have three different FTP connections, just threevariables with values pointing to the some single FTP connection.

* You can't tell much of anything about the object just by looking atthe object value, any more than you can see your credit account balanceby holding the plastic card up to the light, or by adding up the digitsin your credit card number.

* You can't just make up your own object values and have them work ---they can come only from constructor methods of the appropriate class.Similarly, you get a credit card number only by having a bank approveyour application for a credit card account --- at which point theylet you know what the number of your new card is.

Now, there's even more to the fact that you can't just make up your ownobject value: even though you can print an object value and get a stringlike ``Net::FTP=GLOB(0x20154240)'', that string is just arepresentation of an object value.

Internally, an object value has a basically different type from astring, or a number, or the undefined value --- if $x holds a realstring, then that value's slot in memory says "this is a value of typestring, and its characters are...``, whereas if it's an object value,the value's slot in memory says, ''this is a value of type reference,and the location in memory that it points to is..." (and by looking atwhat's at that location, Perl can tell the class of what's there).

Perl programmers typically don't have to think about all these detailsof Perl's internals. Many other languages force you to be moreconscious of the differences between all of these (and also betweentypes of numbers, which are stored differently depending on their sizeand whether they have fractional parts). But Perl does its best tohide the different types of scalars from you --- it turns numbers intostrings and back as needed, and takes the string or numberrepresentation of undef or of object values as needed. However, youcan't go from a string representation of an object value, back to anobject value. And that's why this doesn't work:

   $x = Net::FTP->new('ftp.aol.com');   $y = Net::FTP->new('ftp.netcom.com');   $z = Net::FTP->new('ftp.qualcomm.com');   $all = join(' ', $x,$y,$z);           # !!!  ...later...   ($aol, $netcom, $qualcomm) = split(' ', $all);  # !!!   $aol->login("sburke", "aoeuaoeu");   $netcom->login("sburke", "qjkxqjkx");   $qualcomm->login("smb", "dhtndhtn");

This fails because $aol ends up holding merely the string representationof the object value from $x, not the object value itself --- when"join" tried to join the characters of the ``strings'' $x, $y, and $z,Perl saw that they weren't strings at all, so it gave "join" theirstring representations.

Unfortunately, this distinction between object values and their stringrepresentations doesn't really fit into the analogy of credit cardnumbers, because credit card numbers really are numbers --- eventhought they don't express any meaningful quantity, if you stored themin a database as a quantity (as opposed to just an ASCII string),that wouldn't stop them from being valid as credit card numbers.

This may seem rather academic, but there's there's two common mistakesprogrammers new to objects often make, which make sense only in terms ofthe distinction between object values and their string representations:

The first common error involves forgetting (or never having known in thefirst place) that when you go to use a value as a hash key, Perl usesthe string representation of that value. When you want to use thenumeric value two and a half as a key, Perl turns it into thethree-character string ``2.5''. But if you then want to use that stringas a number, Perl will treat it as meaning two and a half, so you'reusually none the wiser that Perl converted the number to a string andback. But recall that Perl can't turn strings back into objects --- soif you tried to use a Net::FTP object value as a hash key, Perl actuallyused its string representation, like ``Net::FTP=GLOB(0x20154240)'', butthat string is unusable as an object value. (Incidentally, there'sa module Tie::RefHash that implements hashes that do let you usereal object-values as keys.)

The second common error with object values is intrying to save an object value to disk (whether printing it to afile, or storing it in a conventional database file). All you'll get is thestring, which will be useless.

When you want to save an object and restore it later, you may find thatthe object's class already provides a method specifically for this. Forexample, MIDI::Opus provides methods for writing an object to disk as astandard MIDI file. The file can later be read back into memory bya MIDI::Opus constructor method, which will return a new MIDI::Opusobject representing whatever file you tell it to read into memory.Similar methods are available with, for example, classes thatmanipulate graphic images and can save them to files, which can be readback later.

But some classes, like Business::US_Amort, provide no such methods forstoring an object in a file. When this is the case, you can tryusing any of the Data::Dumper, Storable, or FreezeThaw modules. Usingthese will be unproblematic for objects of most classes, but it may runinto limitations with others. For example, a Business::US_Amortobject can be turned into a string with Data::Dumper, and that stringwritten to a file. When it's restored later, its attributes will beaccessible as normal. But in the unlikely case that the loan object wassaved in mid-calculation, the calculation may not be resumable. This isbecause of the way that that particular class does its calculations,but similar limitations may occur with objects from other classses.

But often, even wanting to save an object is basically wrong --- what wouldsaving an ftp session even mean? Saving the hostname, username, andpassword? current directory on both machines? the local TCP/IP portnumber? In the case of ``saving'' a Net::FTP object, you're better offjust saving whatever details you actually need for your own purposes,so that you can make a new object later and just set those values for it. 

So Why Do Some Modules Use Objects?

All these details of using objects are definitely enough to make youwonder --- is it worth the bother? If you're a module author, writingyour module with an object-oriented interface restricts the audience ofpotential users to those who understand the basic concepts of objectsand object values, as well as Perl's syntax for calling methods. Whycomplicate things by having an object-oriented interface?

A somewhat esoteric answer is that a module has an object-orientedinterface because the module's insides are written in anobject-oriented style. This article is about the basics ofobject-oriented interfaces, and it'd be going far afield to explainwhat object-oriented design is. But the short story is thatobject-oriented design is just one way of attacking messy problems.It's a way that many programmers find very helpful (and which othershappen to find to be far more of a hassle than it's worth,incidentally), and it just happens to show up for you, the module user,as merely the style of interface.

But a simpler answer is that a functional interface is sometimes ahindrance, because it limits the number of things you can do at once ---limiting it, in fact, to one. For many problems that some modules aremeant to solve, doing without an object-oriented interface would be likewishing that Perl didn't use filehandles. The ideas are rather simpler--- just imagine that Perl let you access files, but only one at atime, with code like:

  open("foo.txt") || die "Can't open foo.txt: $!";  while(readline) {    print $_ if /bar/;  }  close;

That hypothetical kind of Perl would be simpler, by doing withoutfilehandles. But you'd be out of luck if you wanted to read fromone file while reading from another, or read from two and print to athird.

In the same way, a functional FTP module would be fine for justuploading files to one server at a time, but it wouldn't allow you toeasily write programs that make need to use several simultaneoussessions (like ``look at server A and server B, and if A has a filecalled X.dat, then download it locally and then upload it to server B ---except if B has a file called Y.dat, in which case do it the other wayaround'').

Some kinds of problems that modules solve just lend themselves to anobject-oriented interface. For those kinds of tasks, a functionalinterface would be more familiar, but less powerful. Learning to useobject-oriented modules' interfaces does require becoming comfortablewith the concepts from this article. But in the end it will allow youto use a broader range of modules and, with them, to write programsthat can do more.

[end body of article] 

[Author Credit]

Sean M. Burke has contributed several modules to CPAN, about half ofthem object-oriented.

[The next section should be in a greybox:] 

The Gory Details

For sake of clarity of explanation, I had to oversimplify some of thefacts about objects. Here's a few of the gorier details:

* Every example I gave of a constructor was a class method. But objectmethods can be constructors, too, if the class was written to work thatway: $new = $old->copy, $node_y = $node_x->new_subnode, or the like.

* I've given the impression that there's two kinds of methods: objectmethods and class methods. In fact, the same method can be both,because it's not the kind of method it is, but the kind of calls it'swritten to accept --- calls that pass an object, or calls that pass aclass-name.

* The term ``object value'' isn't something you'll find used much anywhereelse. It's just my shorthand for what would properly be called an``object reference'' or ``reference to a blessed item''. In fact, peopleusually say ``object'' when they properly mean a reference to that object.

* I mentioned creating objects with constructors, but I didn'tmention destroying them with destructor --- a destructor is a kind ofmethod that you call to tidy up the object once you're done with it, andwant it to neatly go away (close connections, delete temporary files,free up memory, etc). But because of the way Perl handles memory,most modules won't require the user to know about destructors.

* I said that class method syntax has to have the class name, as in$session = Net::FTP->new($host). Actually, you can instead use anyexpression that returns a class name: $ftp_class = 'Net::FTP'; $session= $ftp_class->new($host). Moreover, instead of the method name forobject- or class-method calls, you can use a scalar holding the methodname: $foo->$method($host). But, in practice, these syntaxes arerarely useful.

And finally, to learn about objects from the perspective of writingyour own classes, see the "perltoot" documentation,or Damian Conway's exhaustive and clear book Object Oriented Perl(Manning Publications 1999, ISBN 1-884777-79-1). 

BACK

Return to the HTML::Tree docs.


 

Index

NAME
SYNOPSIS
DESCRIPTION
A User's View of Object-Oriented Modules
Modules and Their Functional Interfaces
Modules with Object-Oriented Interfaces
What Can You Do with Objects?
What's in an Object?
What is an Object Value?
So Why Do Some Modules Use Objects?
[Author Credit]
The Gory Details
BACK

This document was created byman2html,using the manual pages.