Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??

Blessables

Creating a Perl object is tremendously easy -- you just bless a reference. While most objects you'll run across are built out of anonymous hashes, there are (at least) six other things you can bless. Here's a list of the whats, the hows, and at least some of the whys.

Arrays

It's surprisingly easy to build a workable class out of an array. There are two strong benefits and one minor drawback to this. On the plus side, internal access performance improves as the overhead of hashing a key and doing a lookup on the key is avoided. Another benefit is that data is more protected via encapsulation (a user of your class will have a more difficult time autovivifying a data member of your class accidentally or purposefully with an array). The drawback is that you will have to know which data member is stored in which slot of the array. Here's an example:
package Soldier; use constant NAME => 0; use constant RANK => 1; use constant SERIAL => 2; sub new { my $class = shift; $class = ref($class) || $class; my $self = [ "", "Private", 000 ]; bless($self, $class); return $self; } sub name { my $self = shift; if (@_) { $self->[NAME] = shift; } return $self->[NAME]; } # similar methods for RANK and SERIAL

Scalars

An excellent example provided in Damian Conway's Object Oriented Perl is that of an object oriented password. All that is necessary in the way of data is the password string, so why not use a simple scalar?
package Password; use Digest::MD5 qw(md5_base64); # based on an idea by jbontje sub new { my $class = shift; $class = ref($class) || $class; my $self = shift; # takes a cleartext string for the passwo +rd $self = md5_base64($self); bless($self, $class); return $self; } sub verify { my $self = shift; my $candidate = shift; return ($self eq md5_base64($candidate)); }
Any cryptographic implementation would do -- in fact, one could extend this class to use a different technique, if desires. Simply add an encrypt() method, and call that in new() and verify().

Regular Expressions

Perl 5.005's new qr{} operand allows regular expressions to be precompiled. (Maybe someday s{}{} will work for substitutions. I thought it might when I first prepared this tutorial, but it doesn't.) They're now fair game for blessing. One might code a word search problem something like this:
package WordMatch; sub new { my $class = shift; $class = ref($class) || $class; my $word = shift; # word to match my $self = qr/\[$word\]/; bless($self, $class); return $self; } sub match { my $self = shift; my $string = shift; return $string =~ $self ? "Matches!" : "Doesn't match!"; } package main; my $wm = WordMatch->new("hi"); print $wm->match("[hi] how are you?"), "\n"; print $wm->match("hi how are you?"), "\n";

Typeglobs

This is the method used in many IO:: packages, such as IO::File. The reason for blessing a typeglob is usually to get at the filehandle associated with that typeglob. We might build a file reader like this:
package ReadFile; use Symbol; sub new { my $class = shift; $class = ref($class) || $class; my $file = shift; my $self = gensym; open ($self, $file) || die; bless($self, $class); return $self; } sub read_record { my $self = shift; local $/ = shift || $/; my $line = <$self>; return $line; }
To test it, you might use:
my $file = ReadFile->new("obself.pl"); print $file->read_record("package"); print $file->read_record();
The constructor takes the name of the file to open, and the read_record() method takes an alternate input record separator. (Symbol::gensym returns a reference to an anonymous typeglob -- if you were wondering.) It would be good to add a DESTROY method to close the typeglob:
sub DESTROY { my $self = shift; close $self; print "Closed!\n"; # just to prove that it's working }

Subroutines

Consider a subroutine browser. Delving deeply into your source code, you might be able to extract argument lists and return values, if you comment diligently and intelligently:
package SubBrowser; sub new { my $class = shift; $class = ref($class) || $class; my $package = shift; my $subname = shift; # assume $package is a reference to a hash of in-memory source cod +e, # keyed by subroutine name my $sub; eval { $sub = $package->{$subname}; }; # ooh, tricky bless($sub, $class); return $sub; } sub display_args { # get data from $package } sub display_returns { # get data from $package } sub test { my $self = shift; return &$self; }
The methods display_args() and display_returns() can search through the comments at the start of the sub, matching however you mark the arguments passed and the return values. Build a hash of an object for each subroutine in your project, and you can iterate through them quickly and easily. This might be part of your test suite.

Objects

At the most bizarre end of the scale, one can even bless a reference to an object. Here's a quick example showing what can be done with our WordMatch object above:
package Wrapper; use vars '$AUTOLOAD'; sub new { my $class = shift; $class = ref($class) || $class; my $obj = shift; my $self = \$obj; bless($self, $class); return $self; } sub AUTOLOAD { my $self = shift; return if $AUTOLOAD =~ /::DESTROY/; $AUTOLOAD =~ s/.*:://; no strict 'refs'; print "Do something interesting here.\n"; return $$self->$AUTOLOAD(@_); } package main; # as before my $wm = WordMatch->new("hi"); print $wm->match("[hi] how are you?"), "\n"; print $wm->match("hi how are you?"), "\n"; # our new version my $wm2 = Wrapper->new(WordMatch->new("Hello")); print $wm2->match("[Hello] little girl"), "\n";
What does this give us over inheritance? Not a whole lot, at first glance. The AUTOLOAD mechanism uses symbolic references and has a performance penalty. (This can be alleviated somewhat by mucking about in the symbol table.)

What if the Wrapper class enforced security, though? If the only interface to an otherwise-private-only-by-politeness object were through this Wrapper class, no one would be able to reach inside the object and do bad things. We could hold a reference to the wrapped object in a variable declared in the use vars statement, making it accessible only through the defined Wrapper interface. We could write some an exception handling wrapper around modules known to be buggy or insecure.

You could do lots of things.... You may never need any of these trickeries, but aren't you glad to know they're available?


In reply to Blessables -- What Can You Make Into Objects? by chromatic

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • Outside of code tags, you may need to use entities for some characters:
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others perusing the Monastery: (6)
    As of 2014-09-21 10:44 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      How do you remember the number of days in each month?











      Results (168 votes), past polls