Previous Page Next Page

14.6. Using Objects from the Perl Library

In Chapter 12, "Modularize It, Package It, and Send It to the Library!" we first looked into the standard Perl library that was provided with this distribution, Perl 5.6. In that library were a number of .pl and .pm files. The examples covered dealt with packages that did not require knowledge about Perl's use of objects. Those files utilized standard subroutines, not methods. Now that you know how objects and methods are used in Perl, the following examples will demonstrate how to use those modules that require the OOP methodology.

14.6.1. Another Look at the Standard Perl Library

The @INC array contains the pathnames to the libraries Perl will search. After looking at the library listings, we will cd into the standard Perl library and list the files found there. You'll notice that some of the files end with the .pm extension and some end with the .pl extension. The files that utilize objects (ending in .pm) were introduced in Perl 5 and are the modules that support OOP. The files that do not have an extension are the names of directories where Perl has stored modules that fit into that category. For example, the File and Math subdirectories contain modules that pertain to those respective subjects.

Example 14.27.

      1   $  perl -e "print join qq/\n/,@INC;"
          c:/Perl/lib
          c:/Perl/site/lib

      2   $ ls /Perl/lib
AnyDBM_File.pm   Exporter.pm     Symbol.pm       cacheout.pl      newgetopt.pl
AutoLoader.pm    ExtUtils        Sys             charnames.pm     open.pm
AutoSplit.pm     Fatal.pm        Term            chat2.pl         open2.pl
B                Fcntl.pm        Test            complete.pl      open3.pl
B.pm             File            Test.pm         constant.pm      ops.pm
Benchmark.pm     FileCache.pm    Text            ctime.pl         overload.pm
ByteLoader.pm    FileHandle.pm   Thread          diagnostics.pm   perl5db.pl
CGI              FindBin.pm      Thread.pm       dotsh.pl         perllocal.pod
CGI.pm           Getopt          Tie             dumpvar.pl       pwd.pl
CORE             I18N            Time            exceptions.pl    re.pm
CPAN             IO              UNIVERSAL.pm    fastcwd.pl       shellwords.pl
CPAN.pm          IO.pm           User            fields.pm        sigtrap.pm
Carp             IPC             Win32.pod       filetest.pm      stat.pl
Carp.pm          Math            XSLoader.pm     find.pl          strict.pm
Class            Net             abbrev.pl       finddepth.pl     subs.pm
Config.pm        O.pm            assert.pl       flush.pl         syslog.pl
Cwd.pm           Opcode.pm       attributes.pm   ftp.pl           tainted.pl
DB.pm            POSIX.pm        attrs.pm        getcwd.pl        termcap.pl
Data             POSIX.pod       auto            getopt.pl        timelocal.pl
Devel            Pod             autouse.pm      getopts.pl       unicode
DirHandle.pm     SDBM_File.pm    base.pm         hostname.pl      utf8.pm
Dumpvalue.pm     Safe.pm         bigfloat.pl     importenv.pl     utf8_heavy.pl
DynaLoader.pm    Search          bigint.pl       integer.pm       validate.pl
English.pm       SelectSaver.pm  bigrat.pl       less.pm          vars.pm
Env.pm           SelfLoader.pm   blib.pm         lib.pm           warnings
Errno.pm         Shell.pm        bytes.pm        locale.pm        warnings.pm
Exporter         Socket.pm       bytes_heavy.pl  look.pl


      3   $ cd Math
      4   $ ls
          BigFloat.pm   BigInt.pm     Complex.pm     Trig.pm

					  

Explanation

  1. The elements of the @INC array are printed to ensure that the standard Perl library is included in Perl's library search path.

  2. The library routines are listed.

  3. Any file not ending in .pl or .pm is a subdirectory. We change to the Math subdirectory.

  4. The contents of the directory are listed, showing three Math modules.

14.6.2. An Object-Oriented Module from the Standard Perl Library

The following module, BigFloat.pm, allows the use of floating point numbers of arbitrary length. Number strings have the form /[+-]\d*\.?\d*E[+-]\d+/. When NaN is returned, it means that a non-number was entered as input, that you tried to divide by zero, or that you tried to take the square root of a negative number. BigFloat uses the overload module, which allows Perl's built-in operators to be assigned methods that will cause the operators to behave in a new way. The operator is the key and the method assigned is the value. (See overload.pm in the standard Perl library.)

Example 14.28.

(The File: BigFloat.pm)

1   package Math::BigFloat;
2   use Math::BigInt;

    use Exporter;  # Just for use to be happy
    @ISA = (Exporter);

3   use overload
4   '+'    =>  sub {new Math::BigFloat &fadd},
    '-'    =>  sub {new Math::BigFloat
                $_[2]? fsub($_[1],${$_[0]}) : fsub(${$_[0]},$_[1])},
    '<=>'  =>  sub {new Math::BigFloat
                $_[2]? fcmp($_[1],${$_[0]}) : fcmp(${$_[0]},$_[1])},
    'cmp'  =>  sub {new Math::BigFloat
                $_[2]? ($_[1] cmp ${$_[0]}) : (${$_[0]} cmp $_[1])},
    '*'    =>  sub {new Math::BigFloat &fmul},
    '/'    =>  sub {new Math::BigFloat
                $_[2]? scalar fdiv($_[1],${$_[0]}) :
                   scalar fdiv(${$_[0]},$_[1])},
    'neg'  =>  sub {new Math::BigFloat &fneg},
    'abs'  =>  sub {new Math::BigFloat &fabs},
    qw(
        ""   stringify
        0+   numify)   # Order of arguments unsignificant
        ;

5   sub new {
       my ($class) = shift;
       my ($foo) = fnorm(shift);
6      panic("Not a number initialized to Math::BigFloat")
              if $foo eq "NaN";
7      bless \$foo, $class;
    }

     < Methods continue here. Module was too long to put here>

    # addition
8   sub fadd { #(fnum_str, fnum_str) return fnum_str
       local($x,$y) = (fnorm($_[$[]),fnorm($_[$[+1]));
       if ($x eq 'NaN' || $y eq 'NaN') {
          NaN';
       } else {
           local($xm,$xe) = split('E',$x);
           local($ym,$ye) = split('E',$y);
           ($xm,$x e,$ym,$ye) = ($ym,$ye,$xm,$xe) if ($xe < $ye);
           &norm(Math::BigInt::badd($ym,$xm.('0' x ($xe-$ye))),$ye);
       }
    }

     < Methods continue here>

    # divisionbb
    # args are dividend, divisor, scale (optional)
    # result has at most max(scale, length(dividend),
    # length(divisor)) digits

9   sub fdiv    #(fnum_str, fnum_str[,scale]) return fnum_str
    {
       local($x,$y,$scale) = (fnorm($_[$[]),
                              fnorm($_[$[+1]),$_[$[+2]);
       if ($x eq 'NaN' || $y eq 'NaN' || $y eq '+0E+0') {
           'NaN';
       } else {
          local($xm,$xe) = split('E',$x);
          local($ym,$ye) = split('E',$y);
          $scale = $div_scale if (!$scale);
          $scale = length($xm)-1 if (length($xm)-1 > $scale);
          $scale = length($ym)-1 if (length($ym)-1 > $scale);
          $scale = $scale + length($ym) - length($xm);
          &norm(&round(Math::BigInt::bdiv($xm.('0' x $scale),$ym),
                                          $ym),$xe-$ye-$scale);
       }
    }

					  

Explanation

  1. The BigFloat class is declared. It resides in the Math subdirectory of the standard Perl library.

  2. The BigFloat class also needs to use the BigInt module.

  3. The overload function allows you to change the meaning of the built-in Perl operators. For example, when using BigFloat.pm, the + operator is a key and its value an anonymous subroutine that creates an object and calls the &fadd subroutine.

  4. The + operator is overloaded. See previous explanation.

  5. This is BigFloat's constructor method for creating an object.

  6. If the value is not a number, this panic message is printed.

  7. The object is blessed into the class.

  8. This is the subroutine that performs addition on the object.

  9. This is the subroutine that performs division on the object.

 

14.6.3. Using a Module with Objects from the Standard Perl Library

Example 14.29.

1   #!/bin/perl
2   use Math::BigFloat;  # BigFloat.pm is in the Math directory

3   $number = "000.95671234e-21";
4   $mathref = new Math::BigFloat("$number");  # Create the object

5   print "\$mathref is in class ", ref($mathref), "\n";
                      # Where is the object

6   print $mathref->fnorm(), "\n";  # Use methods from the class

7   print "The sum of $mathref + 500 is: ", $mathref->fadd("500"),
                                         "\n";
8   print "Division using overloaded operator: ", $mathref / 200.5,
                                         "\n";
9   print "Division using fdiv method:", $mathref->fdiv("200.5"),
                                         "\n";

10  print "Enter a number ";
    chop($numstr = <STDIN>);

11  if ( $mathref->fadd($numstr) eq "NaN" ){
                    print "You didn't enter a number.\n"};

# Return value of NaN means the string is not a number,
# or you divided by zero, or you took the square root
# of a negative number.

(Output)
5   $mathref is in class Math::BigFloat
6   +95671234E-29
7   The sum of .00000000000000000000095671234 + 500 is:
    +50000000000000000000000095671234E-29
8   Division using overloaded operator:
    .000000000000000000000004771632618453865336658354114713216957606
9   Division using fdiv method:
    +4771632618453865336658354114713216957606E-63
10  Enter a number hello
11  You didn't enter a number.

					  

Explanation

  1. The shbang line to the Perl interpreter.

  2. The use function loads the module BigFloat.pm into the program. Since this module is in a subdirectory of the library called Math, that subdirectory is included by prepending its name to the module with two colons.

  3. A large number (e notation) is assigned to $number.

  4. Now the methods from the module are utilized. The BigFloat constructor is called. A reference to the object is returned and assigned to $mathref.

  5. The ref function returns the name of the class.

  6. The fnorm method returns the "normal" value of $number in signed scientific notation. Leading zeros are stripped off.

  7. The fadd method adds 500 to the number.

  8. In this example, an overloaded operator is used. The / operator is assigned a class method, fdiv, to perform the division. See code from BigFloat.pm shown above.

  9. This time the fdiv method is called directly without using overloading to perform the division. The output is slightly different.

  10. The user is asked to enter a number.

  11. If NaN (not a number) is returned from the fadd method, the message is printed. This is a way you could check that user input is a valid numeric value.

Previous Page Next Page