: -----Original Message-----
: From: owner-cgi-list@jann.com [mailto:owner-cgi-list@jann.com]
: On Behalf Of Vuillemot, Ward W
: Sent: Tuesday, December 18, 2001 10:59 AM
: To: cgi-list@jann.com
: Subject: [CGI] OT using use with variables
:
:
: According to www.perldoc.com regarding 'use', I believe
: you must use barewords for module names. Is this correct?
:
: I want to do something like
:
: &$app::main($var1,$var2);
:
: where $app is provided elsewhere.
: is there a way to do it? I have tried an eval statement, but it
: fails. doing it directly also fails.
----------------------------------
Answers to both of your questions
appear in like order below:
----------------------------------
: According to www.perldoc.com regarding 'use', I believe you
: must use barewords for module names. Is this correct?
No, not correct. You use "package names". (eg- glorified "barewords").
The package name which follows the use() command corresponds to the
name of the module wherein that external code resides. Package names
tell Perl which "package" or namespace to look in for the variables and
methods of the module who's name is the same as the package it holds.
CGI.pm holds the CGI package. CGI::param() is the method which you use
to collect data passed to your script from a form or a query string.
CGI::new() is the method you use in order to create new CGI objects.
When you use methods, variables, and other things from Perl modules,
you should call them with the arrow syntax as shown in the example code
below. That syntax forces Perl to pass the package name to the
constructor method inside that external module as the first argument
which that method receives in its @_.
Modules are built to expect this. The package name which is implicitly
passed to the method in your module (when the arrow syntax is used)
tells Perl the namespace wherein that code resides. That helps the
ModuleX::new() # constructor method
method gain access to its other methods and variables so it can carry
out tasks which it might pass to other routines in the same module when
you call it from your script.
For example, CGI::new() uses lots of other routines in its namespace
in order to initialize each new CGI object with all of the elements
you'd expect a CGI object to have. CGI::new() has to store data about
the CGI environment (%ENV), data about the way it was called (@ARGV),
data submitted from forms, query strings, or even from the command
line. If CGI::new needs to get to its those other methods, it could use
that package name which Perl sent to it (along with any other arguments
you passed yourself when you called it) in order to find where those
methods are. When you have Perl pass a package name by using the arrow
operator, CGI::new knows where to look to find its other methods.
It knows that its param method is at CGI::param, and can tell Perl to
go there and not be confused with any other subroutine in your script
or in other modules which might happen to be named 'param' as well.
: I want to do something like
:
: &$app::main($var1,$var2);
:
: where $app is provided elsewhere.
: is there a way to do it? I have tried an eval statement,
: but it fails. doing it directly also fails.
Solution:
$app->main($var1,$var2) if (UNIVERSAL::isa($app,'login');
Make sure that app::main() is expecting a reference to it's namespace.
Perl will send it one when you call it with the arrow, which is what
you should do if $app::main holds a reference to your module.
You see, when you call a module with a package name and an arrow ( eg-
CGI->new() ), Perl stuffs that package name into the @_ which
CGI::new() receives. That way CGI::new() can create a new CGI object
with that package name. The object it creates is, of course, named
CGI.
CGI::new(), and every other module you use will normally pass you back
a reference to the new object it just made with its package name that
you provided. You can use that reference to the new CGI object to get
a cached version of any of the code inside it. Otherwise, if you
always use CGI.pm in a manner where you call its methods like normal
subroutines (eg- CGI::param(), CGI::header(), etc.) Perl will not give
you the same benefits of using modular OO code objects. In fact, you
just end up with a very bloated script.
Once you have a reference to the new precompiled CGI object (NOT the
same as a simple imported code library! This is discussed below) you
can use that reference to call those cached methods. When you call
those pre-cached methods inside your object with the reference to it
which your constructor method sent back (the constructor method is
CGI::new() ) Perl will now pass those methods a reference of their own
as the first argument in their @_.
This is why all methods or 'routines' in modules usually start out with
the same argument:
my($self) = shift;
Where Perl first passed a string containing the package name to
CGI::new when you called it with the arrow ( CGI->new() ), it now
passes its methods a reference to the 'CGI' package name when you call
them with the reference you got back from CGI::new().
These object methods expect that their first argument is the reference
to the CGI object which you made with CGI::new(), and now that method
can call all of its friends without bogging down the Perl interpreter
by making it create a new copy of the code inside them each time they
are called. Those methods also need access to the object which
CGI::new() created for you. They want the benefits of using that
pre-compiled code as well.
They don't want to call the other methods in CGI.pm or ask for the
other package variables in CGI.pm without that reference because Perl
will have to create a whole copy of those subroutines and variables
each time you do.
And this is where the benefit of OO programming is manifest, and why
well designed modules make scripts faster than they could otherwise
have been. Objects are faster. Objects are compiled once, used over
and over as many times as you want, they make your scripts cleaner,
they make your development more quick and easy, and when you throw away
the reference to them, Perl frees up the memory which held that object
for the rest of your script to use. Use once and again, then throw
them away to make room and reserve resources for more, or for your
script. Objects are the bomb! You never get that benefit when you
don't use Objects. When you don't use objects in your programming and
your scripts use any of its subroutines more than one time, you are
quite often making your script slower and making Perl work harder than
it needs to.
When you use a module correctly, you get a script that runs (and looks)
"like a streamlined butterfly." It will work much more cleanly,
execute much more rapidly, and only compile the methods you need.
Modules like CGI.pm are not only well known, but well designed. CGI.pm
is so smart that it only lets Perl compile a very limited portion of
its internals when called correctly like:
CGI->new()
and only if you ever ask it for one of its less-used methods, such as
the ones used to create HTML for you, will it ever load them into the
executing process and run them for you. CGI.pm is smarter than the
average bear --and smarter than the majority of those who use it too
:o)
As a quick review, we'll look at a quick code example and be done with
it. You can ask me any questions if the code or the text of this post
was confusing... and it may be confusing if I wrote it!
Let's say our script uses my handy File utilities module from the
Atrixnet Perl archives...
# use File utilities module
use Futils;
# make a new Futils object, and store the
# reference to its package name which the
# Futils::new() subroutine will return
my($objectref) = Futils->new();
Now inside Futils.pm, Futils::new() grabs that special reference which
Perl passes to it when we called it with an arrow in our script.
# --------------------------------------------------------
# Futils::new()
# --------------------------------------------------------
sub new {
# This is the 'constructor method', or 'the object
# oriented subroutine used to make new Futils objects'
[note- this is a simplified version of the actual Futils code]
my($class) = shift;
my($this) = {};
# Make a new Futils object with out of the variable
# named '$this', and name it after the package name
# that was sent to us from the caller and just saved
# in '$class''. That package name happens to be...
#
# ...drum roll please...
# "Futils" !!!
# Or in OO speak, tell Perl to "bless()" the variable
# named '$this' to become a new object or "instance"
# of the code inside the 'Futils' package namespace.
# (I liked the first explanation better.)
bless($this, $class);
# now that Perl has made a sleek new Futils object, it
# gives us a reference to it by turning '$this' into
# the new object, saving it in memory for its greedy
# little self, and then only giving us back a reference
# to it. (kind of like, "My parents went to Niagara Falls
# and all I got was this lousy T-shirt") That reference
# just happens to be returned to us when Perl keeps the
# object for us in memory, and sends us back a reference
# to it really sneaky by stuffing it into '$this'
# Now we'll share it with others:
# return the reference to this object back to
# the caller...
return($this);
}
Quick code explanation:
Futils knows it is going to get its package name from the caller, so it
grabs that as its first argument and saves it in a variable.
It then bless()-s a separate variable into object-hood using the
package namespace which Perl passed to it with any other arguments you
may have passed as well. In other words, Perl creates a new object
named Futils, and sends the caller a reference to the new object.
-Tommy Butler, consultant
Atrixnet, for Internet Business Software
http://atrixnet.com
2200 North Lamar
Suite 307
Dallas, TX
75202
--
Visit the open source Perl archives at Atrixnet
http://www.atrixnet.com/pub/