Solved

Subroutine library calls in Perl

Posted on 2003-11-20
7
726 Views
Last Modified: 2013-12-25
In Perl, I have created a file containing several shared subroutines ("subrout.lib") and then including the command "require 'subrout.lib';" in each script that references one or more of the subroutines.  That works well except when a script calls itself (for instance, to replot the screen with the data sorted differently).  It clearly accesses the subroutines the first time, but does not access them in subsequent calls.

When I include the shared subroutines in each script, everything works fine.  That obviously increases the size of my scripts and is no fun to maintain.  Before I proceed, I thought I would ask what is the best way to (a) set up a library of subroutines and (b) call a subroutine from that library.
0
Comment
Question by:ryuuseki
7 Comments
 
LVL 5

Assisted Solution

by:djplaistow
djplaistow earned 50 total points
ID: 9791156
For a package named DBUtilities, which by convention would be stored in a file named DBUtilities.pm, the begining would look like:

    package DBUtilities;

    require Exporter;
    @ISA = qw(Exporter);
    @EXPORT = (SqlFunction AnotherFunc); # List all subroutines and variables that will be automatically
                                                                   # exported to all scripts that use the module
    @EXPORT_OK = qw(Func1 $globalDsn  @tables); # List all subroutines and variables that will be exported
                                                                                  # to all scripts that explicitly name them

Then a script that wants to use subroutines and/or variables that are within DBUtilities would add a line like:

    use DBUtilities qw(SqlFunction @tables);

Thus, the script will have acces to the subroutines SqlFunction (which it did not have to explicitly request),  and AnotherFunc, and the variable @tables. However, it will not have access to the subroutine Func1 or the variable $globalDsn as it would have had to explicitly request them.
0
 
LVL 5

Assisted Solution

by:djplaistow
djplaistow earned 50 total points
ID: 9791186
I forgot to spell out the answer to "(b) call a subroutine from that library." Once you have included the line like:

    use DBUtilities qw(SqlFunction @tables);

You treat it as if the code for the function is within the script itself; it is analogous to the C++ using namespace construct.
0
 
LVL 84

Assisted Solution

by:ozo
ozo earned 25 total points
ID: 9791726
How does it fail when a script calls itself?
Could you give an example of code that does not work the way you think it should?
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 51

Assisted Solution

by:ahoffmann
ahoffmann earned 25 total points
ID: 9800243
before converting to packages, could you please post the require and the exec (itself) part of your script
0
 

Author Comment

by:ryuuseki
ID: 9819929
I appreciate the comments.  Honestly, I was hoping there would be a simpler answer than working with packages.

In theory, should the calls using require work?  Is there any inherent problem with this method?  The scripts are on our internal server, and too large to post in this forum.  I can try to write a smaller script that replicates the failure, but I'd rather put my efforts toward proper technique if this method is not recommended.
0
 

Author Comment

by:ryuuseki
ID: 9820690
*sigh*  Just when I think I understood something, I realize I really didn't.

The failure appears to be related to the scoping of "my" variables.  I have always used strict scoping with "my" variables.  What I didn't quite understand was the concept of packaged scoping of the "my" vars.

Simply put, in the following example, $v2 is visible to the subroutine "test":

(main.pl)
use strict;
my($v1) = "VAR 1";
my($v2) = "VAR 2";
print "$v1\n";
print "$v2\n";
&test();

sub test {
  print "$v2\n"; }

If I change it to the following, $v2 is not visible to "test":

(main.pl)
use strict;
require "subrout.lib";
my($v1) = "VAR 1";
my($v2) = "VAR 2";
print "$v1\n";
print "$v2\n";
&test();

(subrout.lib)
sub test {
  print "$v2\n"; }

1;

By changing "my($v2)" to "our($v2)" it becomes visible outside of the "main" package.

I'm still not sure why the complicated script works the first time through but not on subsequent calls.  I'll have to dig deeper to figure that out.


In the meantime, I'd still appreciate comment regarding my previous comment re: the propriety of using require.
0
 
LVL 3

Accepted Solution

by:
rkosai earned 25 total points
ID: 9827046
To allieviate problems such as these, as well as making code easier to read (and following "better" coding practices), it is usually recommended to make each of your subroutines isolated from each other.  This avoids many problems, including ones like this.

So, alternatively, you'd write code like this.

use strict;
require "subrout.lib";
my $v1 = "VAR 1";
my $v2 = "VAR 2";
print "$v1\n";
print "$v2\n";
test($v2); #prints $v2

# -- (subrout.lib) --
sub test {
  shift; #captures the arguments to the subroutine, and stores them in $_
  print "$_\n"; }

1;
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

Introduction:   Welcome to my first article ever. To begin with, the reason I write this article.  I participated in a question on Experts Exchange about the start command in Windows and there were some discussion about the usage. The discussio…
It is a general practice to get rid of old user profiles on a computer  in a LAN environment. As I have been working with a company in a LAN environment where users move from one place to some other place at times. This will make many user profil…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now