|
Some of the techniques used
in the text might not be obvious to new Perl
converts. The three boxes in this article explain
some of the ones which might most baffle newcomers.
The techniques introduced here are by no means
obscure hacks-they are well-documented and stable
features of Perl that you can rely on in the future.
It's just that they are unexpectedly practical for
people who are used to other languages where there is
only one way of doing things.
Because Perl is so dynamic,
you can do many things while your program is running
(run-time) as opposed to when the Perl compiler is
reading your program (compile-time). The parser takes
advantage of this, letting you choose classes on the
fly. Consider this program:
package A; sub foo {print "You called the sub A::foo\n"}
package B; sub foo {print "The routine B::foo was called\n"}
package main; $ARGV[0]->foo();
There are two foo() methods here; which
one is called depends on what argument (A or
B) you provide on the command line. Even
though this little program doesn't explicitly pass
any parameters to foo(), Perl adds one for
you: all subroutines called in this manner receive is
the name of the caller's package as the first
parameter. This might seem silly - after all, we know
which package the function is in - but there is
actually a very good use for this: inheritance.
package A; sub foo {print "You called A::foo through package $_[0]\n"}
package B; @ISA = ('A');
package C; @ISA = ('A');
package main; $ARGV[0]->foo();
In this case, the subroutine A::foo is
invoked on any call to A::foo,
B::foo, or C::foo. But because of
that first parameter, it knows where it was called
from, and can operate differently if necessary. This
might again seem pointless-why don't we just call
A::foo with that argument in the first
place? Again, there is a reason for doing it like
this. Suppose that A::foo implements the
same things asB::foo, but in a slower and
more general fashion. In this case, we can first
prototype the system with code like the above and
later replace B::foo with something quick
and specific. The advantage is that we won't have to
change any other code. If we had hardcoded
A::foo with the parameter, we would now have
to either change the calls or make A::foo
more complicated. (This is exactly what happened with
the FreeWRL code for multiple-valued fields.)
Of course, it is possible to achieve similar
things in C++, or Java (using inheritance), or C
(using function pointers). However, in Perl the
packages do not need to be related in any way before
runtime (Java can do that too, but only in a more
complicated way). See the perlmod and
perlobj documentation for more detail.
|