disappearing arguments when one package function calls another

W

wana

I am packaging a set of commonly used functions to make my code a
little more easy to read. I called a package function with another
package function and the arguments I passed to it were not in @_ as
expected. I imagine if I passed by reference it might work or maybe I
need to use an array global to the package instead of @_, but those
solutions will take away from the simplicity I was hoping for. My
background is in C++ where this would be a normal way of doing things.
I found the chapter on symbol tables and packages in Programming Perl
to be a little confusing, but I thought that's where the answer would
be.


Here's the package (with irrelevant code removed). The problem comes
up when ReplaceInFile('one','two','file1','file2') calls LoadFromFile.
LoadFromFile does not receive any of the passed arguments.

package myfunctions
..
..
..
sub LoadFromFile
#takes array reference and file name as argument
#and clears array and fills array with file contents
{
my ($array, $filename) = @_;
open my $file, '<', $filename or die "Couldn't open $filename:
$!";
@{$array} = <$file>;
close $file or die "Error closing $filename: $!";
}
..
..
..
sub ReplaceInFile
{
#parameters
my $target = shift; #string to search for to replace
my $source = shift; #string to replace with
my $infile = shift;
my $outfile = shift;

#private variables
my @workspace;

LoadFromFile(@workspace,$infile);
foreach(@workspace) {s/$target/$source/g;}
SaveToFile(@workspace,$outfile);
}
1;


Thanks!

wana
 
S

Sherm Pendley

wana said:
sub LoadFromFile
#takes array reference and file name as argument
#and clears array and fills array with file contents
{
my ($array, $filename) = @_;

But you're not passing it a reference. In C++ terms, you're using
pass-by-value here:
LoadFromFile(@workspace,$infile);

To pass a reference to @workspace, you want to do this:

LoadFromFile(\@workspace, $infile);

sherm--
 
P

Paul Lalli

wana said:
I am packaging a set of commonly used functions to make my code a
little more easy to read. I called a package function with another
package function and the arguments I passed to it were not in @_ as
expected. I imagine if I passed by reference it might work or maybe I
need to use an array global to the package instead of @_, but those
solutions will take away from the simplicity I was hoping for.

No they wouldn't. You would be adding exactly one character of code to
pass the array by reference, as it should be.

package myfunctions
.
.
.
sub LoadFromFile
#takes array reference and file name as argument
#and clears array and fills array with file contents

You claim this function takes an array refernece.....
{
my ($array, $filename) = @_;
open my $file, '<', $filename or die "Couldn't open $filename:
$!";
@{$array} = <$file>;
close $file or die "Error closing $filename: $!";
}
.
.
.
sub ReplaceInFile
{
#parameters
my $target = shift; #string to search for to replace
my $source = shift; #string to replace with
my $infile = shift;
my $outfile = shift;

#private variables
my @workspace;

LoadFromFile(@workspace,$infile);

....But here you pass the function an empty list followed by $infile. If
you want LoadFromFile() to modify the array, you must pass a reference
to the array. Otherwise, you are only passing the contents of the array:

LoadFromFile(\@workspace, $infile);
foreach(@workspace) {s/$target/$source/g;}
SaveToFile(@workspace,$outfile);
}
1;

Note that alternatively, you could provide LoadFromFile a prototype that
would specify the arguments it needs to receive:

sub LoadFromFile(\@$) {
#...
}

This would have the effect of automatically creating a reference to the
array passed in (so no further changes would be required to either your
LoadFromFile, nor to ReplaceInFile as you had written it).

Paul Lalli
 
B

Ben Morrow

Quoth (e-mail address removed) (wana):
package myfunctions

All-lowercase top-level package names are reserved for pragmas. Chose
another name, either MyFunctions or (preferably) something more
descriptive.
@{$array} = <$file>;

There's no need for these {}, @$array will work perfectly well. Of
course, it does no harm to leave them in if you find it easier to follow
like that.
sub ReplaceInFile
{
#parameters
my $target = shift; #string to search for to replace
my $source = shift; #string to replace with
my $infile = shift;
my $outfile = shift;

It would be easier to write

my ($target, $source, $infile, $outfile) = @_;

although it will not have quite the same effect (the arguments will not
be removed from @_; in this case it makes no difference).
foreach(@workspace) {s/$target/$source/g;}

This is very bad style. If you want a one-line for loop, use a statement
modifier:

s/$target/$source/g for @workspace;

.. Otherwise, write it properly:

for (@workspace) {
s/$target/$source/g;
}

Ben
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top