How do I pass in a variable from one function into another in perl - perl

I am initializing a variable within one function and would like to pass this variable into another function. This variable holds a char value.
I have tried passing in the referencing and dereferencing, declaring the variables outside of the function, and using local.
I've also looked in perlmonks, perl by example, googled and looked through this site for a solution but to no avail. I'm just starting out with perl programming so any help will be appreciated!

Sounds to me like you need to read through some documentation, not just google around. I would suggest http://www.perl.org/books/beginning-perl/.
use strict;
use warnings;
sub foo {
my $char = 'A';
bar($char);
}
sub bar {
my ($bar_char) = #_;
print "bar got char $bar_char\n";
}
foo();

If you pass a parameter by reference (see below), it can be modified by the first function and you can then pass it to another function:
#!/usr/bin/perl
sub f {
$c = shift;
$$c='m';
}
$c='a';
f(\$c);
print $c;
This will print 'm'

Is there a reason who your first function cannot return this variable?
my $config_variable = function1( $param1 );
function2 ( $config_variable, $param2 );
You can also pass more than one variable back too:
my ( $config_variable, $value ) = function1( $param1 );
my $value2 = function2( $param1, $config_variable );
This would be the best way. However, you can use globally defined variables and they can be used from function to function:
#! /usr/bin/env perl
#
use strict;
use warnings;
my $value;
func1();
func2();
sub func1 {
$value = "foo";
}
sub func2 {
print "Value = $value\n";
}
Note that I declared $value outside of both functions, so it's global in the entire file - even in the subroutines. Now, func1 can set it, and func1 can print it.
The technical term for this is: A terrible, awful, evil idea and you should never, ever1 think of doing it.
This is because a particular variable you think is set to one value suddenly and mysteriously changes values without any reason. Do this for one variable is bad enough, but if you use this as a crutch, you'll end up with dozens of variables that are impossible to track through your program.
If you find yourself doing this quite a bit, you may need to rethink your code logic.

Related

Can I make a variable optional in a perl sub prototype?

I'd like to understand if it's possible to have a sub prototype and optional parameters in it. With prototypes I can do this:
sub some_sub (\#\#\#) {
...
}
my #foo = qw/a b c/;
my #bar = qw/1 2 3/;
my #baz = qw/X Y Z/;
some_sub(#foo, #bar, #baz);
which is nice and readable, but the minute I try to do
some_sub(#foo, #bar);
or even
some_sub(#foo, #bar, ());
I get errors:
Not enough arguments for main::some_sub at tablify.pl line 72, near "#bar)"
or
Type of arg 3 to main::some_sub must be array (not stub) at tablify.pl line 72, near "))"
Is it possible to have a prototype and a variable number of arguments? or is something similar achievable via signatures?
I know it could be done by always passing arrayrefs I was wondering if there was another way. After all, TMTOWTDI.
All arguments after a semi-colon are optional:
sub some_sub(\#\#;\#) {
}
Most people are going to expect your argument list to flatten, and you are reaching for an outdated tool to do what people don't expect.
Instead, pass data structures by reference:
some_sub( \#array1, \#array2 );
sub some_sub {
my #args = #_;
say "Array 1 has " . $args[0]->#* . " elements";
}
If you want to use those as named arrays within the sub, you can use ref aliasing
use v5.22;
use experimental qw(ref_aliasing);
sub some_sub {
\my( #array1 ) = $_[0];
...
}
With v5.26, you can move the reference operator inside the parens:
use v5.26;
use experimental qw(declared_refs);
sub some_sub {
my( \#array1 ) = $_[0];
...
}
And, remember that v5.20 introduced the :prototype attribute so you can distinguish between prototypes and signatures:
use v5.20;
sub some_sub :prototype(##;#) { ... }
I write about these things at The Effective Perler (which you already read, I see), in Perl New Features, a little bit in Preparing for Perl 7 (which is mostly about what you need to stop doing in Perl 5 to be future proof).

Using perl `my` within actual function arguments

I want to use perl to build a document graph as readably as possible. For re-use of nodes, I want to refer to nodes using variables (or constants, if that is easier). The following code works and illustrates the idea with node types represented by literals or factory function calls to a and b. (For simple demo purposes, the functions do not create nodes but just return a string.)
sub a (#) {
return sprintf "a(%s)", join( ' ', #_ );
}
sub b (#) {
return sprintf "b(%s)", join( ' ', #_ );
}
printf "The document is: %s\n", a(
"declare c=",
$c = 1,
$e = b(
"use",
$c,
"to declare d=",
$d = $c + 1
),
"use the result",
$d,
"and document the procedure",
$e
);
The actual and expected output of this is The document is: a(declare c= 1 b(use 1 to declare d= 2) use the result 2 and document the procedure b(use 1 to declare d= 2)).
My problem arises because I want to use strict in the whole program so that variables like $c, $d, $e must be declared using my. I can, of course, write somewhere close to the top of the text my ( $c, $d, $e );. It would be more efficient at edit-time when I could use the my keyword directly at the first mention of the variable like so:
…
printf "The document is: %s\n", a(
"declare c=",
my $c = 1,
my $e = b(
"use",
$c,
"to declare d=",
my $d = $c + 1
),
"use the result",
$d,
"and document the procedure",
$e
);
This would be kind of my favourite syntax. Unfortunately, this code yields several Global symbol "…" requires explicit package name errors. (Moreover, according to documentation, my does not return anything.)
I have the idea of such use of my from uses like in open my $file, '<', 'filename.txt' or die; or in for ( my $i = 0; $i < 100; ++$i ) {…} where declaration and definition go in one.
Since the nodes in the graph are constants, it is acceptable to use something else than lexical variables. (But I think perl's built-in mechanims are strongest and most efficient for lexical variables, which is why I am inclined into this direction.)
My current idea to solve the issue is to define a function named something like define which behind the scenes would manipulate the current set of lexical variables using PadWalker or similar. Yet this would not allow me to use a natural perl like syntax like $c = 1, which would be my preferred syntax.
I am not certain of the exact need but here's one simple way for similar manipulations.
The example in the OP wants a named variable inside the function call statement itself, so that it can be used later in that statement for another call etc. If you must have it that way then you can use a do block to work out your argument list
func1(
do {
my $x = 5;
my $y = func2($x); # etc
say "Return from the do block what is then passed as arguments...";
$x, $y
}
);
This allows you to do things of the kind that your example indicates.†
If you also want to have names available in the subroutine then pass a hash (or a hashref), with suitably chosen key names for variables, and in the sub work with key names.
Alternatively, consider normally declaring your variables ahead of the function call. There's no bad thing about it while there are many good things. Can throw in a little wrapper and make it look nice, too.
† More specifically
printf "The document is: %s\n", a( do {
my $c = 1;
my $d = $c + 1;
my $e = b( "use", $c, "to declare d=", $d );
# Return a list from this `do`, which is then passed as arguments to a()
"declare c=", $c, $e, "use the result", $d,"and document the procedure", $e
} );
(condensed into fewer lines for posting here)
This do block is a half-way measure toward moving this code into a subroutine, as I presume that there are reasons to want this inlined. However, since comments indicate that the reality is even more complex I'd urge you to write a normal sub instead (in which a graph can be built, btw).
according to documentation, my does not return anything
The documentation doesn't say that, and it's not the case.
Haven't you ever done my $x = 123;? If so, you've assigned to the result of my $x. my simply returns the newly created variable as an lvalue (assignable value), so my $x simply returns $x.
Unfortunately, this code yields several [strict vars] errors.
Symbols (variables) created by my are only visible starting with the following statement.
For better of for worse, it allows the following:
my $x = 123;
{
my $x = $x;
$x *= 2;
say $x; # 246
}
say $x; # 123
I want to use perl to build a document graph as readably as possible.
So why not do that? Right now, you are building a string, not a graph. Build a graph of objects that resolve to a string after the graph has been constructed. You can build those object with a tree of sub calls (declare( c => [ use( c => ... ), ... ] )). I'd give a better example, but the grammar of what you are generating isn't clear to me.
Your argument list makes two references each to $c, $d and $e. If you prefix the first reference with my, it will be out of scope by the time Perl gets around to parsing the second reference it won't be in scope until the next statement, so the second reference would refer to a different variable (which may violate strict vars).
Declare my ($c,$d,$e) before your function call. There is nothing wrong or inelegant about doing that.

Can someone explain why Perl behaves this way (variable scoping)?

My test goes like this:
use strict;
use warnings;
func();
my $string = 'string';
func();
sub func {
print $string, "\n";
}
And the result is:
Use of uninitialized value $string in print at test.pl line 10.
string
Perl allows us to call a function before it has been defined. However when the function uses a variable declared only after the function call, the variable appears to be undefined. Is this behavior documented somewhere? Thank you!
The behaviour of my is documented in perlsub - it boils down to this - perl knows $string is in scope - because the my tells it so.
The my operator declares the listed variables to be lexically confined to the enclosing block, conditional (if/unless/elsif/else), loop (for/foreach/while/until/continue), subroutine, eval, or do/require/use'd file.
It means it's 'in scope' from the point at which it's first 'seen' until the closing bracket of the current 'block'. (Or in your example - the end of the code)
However - in your example my also assigns a value.
This scoping process happens at compile time - where perl checks where it's valid to use $string or not. (Thanks to strict). However - it can't know what the value was, because that might change during code execution. (and is non-trivial to analyze)
So if you do this it might be a little clearer what's going on:
#!/usr/bin/env perl
use strict;
use warnings;
my $string; #undefined
func();
$string = 'string';
func();
sub func {
print $string, "\n";
}
$string is in scope in both cases - because the my happened at compile time - before the subroutine has been called - but it doesn't have a value set beyond the default of undef prior to the first invocation.
Note this contrasts with:
#!/usr/bin/env perl
use strict;
use warnings;
sub func {
print $string, "\n";
}
my $string; #undefined
func();
$string = 'string';
func();
Which errors because when the sub is declared, $string isn't in scope.
First of all, I would consider this undefined behaviour since it skips executing my like my $x if $cond; does.
That said, the behaviour is currently consistent and predictable. And in this instance, it behaves exactly as expected if the optimization that warranted the undefined behaviour notice didn't exit.
At compile-time, my has the effect of declaring and allocating the variable[1]. Scalars are initialized to undef when created. Arrays and hashes are created empty.
my $string was encountered by the compiler, so the variable was created. But since you haven't executed the assignment yet, it still has its default value (undefined) during the first call to func.
This model allows variables to be captured by closures.
Example 1:
{
my $x = "abc";
sub foo { $x } # Named subs capture at compile-time.
}
say foo(); # abc, even though $x fell out of scope before foo was called.
Example 2:
sub make_closure {
my ($x) = #_;
return sub { $x }; # Anon subs capture at run-time.
}
my $foo = make_closure("foo");
my $bar = make_closure("bar");
say $foo->(); # foo
say $bar->(); # bar
The allocation is possibly deferred until the variable is actually used.

How to properly declare global variables in Perl?

I am trying to understand variable scope and properly declaring variables in Perl, and I am having a hard time.
The code below basically reads in an excel file, parses it, and spits it out to a new excel file.
However, I am trying to read one of the headers, and if the header matches my string, I want to record that column number, and use it later in the code.
I am getting a "Use of uninitialized value $site_name_col in print at ./parser.pl line 38."
Line 38 is "print $site_name_col;"
I realize this print statement is outside the {} where the variable was initially initialized, but it was declared as a global variable at the beginning of the code, so what gives?
#!/usr/bin/perl -w
use strict;
use warnings;
use vars qw($site_name_col);
use Spreadsheet::WriteExcel;
use Spreadsheet::ParseExcel;
my ($fname1) = #ARGV;
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse($fname1);
my $new_workbook = Spreadsheet::WriteExcel->new('formated_list.xls', $fname1);
if (!defined $workbook) {
die $parser->error(), ".\n";
}
for my $worksheet ( $workbook->worksheets() ) {
my ($wsheet_name) = $worksheet->get_name();
my $new_worksheet = $new_workbook->add_worksheet($wsheet_name);
my ($row_min, $row_max) = $worksheet->row_range();
my ($col_min, $col_max) = $worksheet->col_range();
for my $row ($row_min .. $row_max) {
for my $col ($col_min .. $col_max) {
my $cell = $worksheet->get_cell($row, $col);
next unless $cell;
print "Row, Col = ($row, $col)\n";
if ( $cell->value() =~ /Site Name/ ) {
$site_name_col = $col;
}
print $site_name_col;
$new_worksheet->write($row, $col, $cell->value());
}
}
}
$new_workbook->close();
use vars qw() Is not recommended any more. To declare a global variable use our $my_var
Your problem may be comes from the condition $cell->value() =~ /Site Name/ . It is probably never met so your variable never gets a value.
i recognize this post is a little old, but...for those still coming to this page years later (like myself):
i imagine these excel worksheets you were reading in may not have been created by you. so, you may encounter casing issues, and regexes are case sensitive, of course. either uppercase or lowercase the data during the check: if (lc($cell->value()) =~ /site name/) ...
use our! there are lots of reasons for one to have a global. site_name would seem to be something all files might need...
Jarett
edit:
this will work much better:
if ($cell->value()) =~ /site name/i) { print $col; }
no need to print outside the if statement at all...saves printing nothing many...many times....
Just to clarify what others have already said, a variable declared at the top of a file with my is accessible and usable by your entire file. There is no reason for a global variable in this case.
When would you want a global?
You want a variable to be accessible by another piece of code outside of your file. For example, a module might provide a global variable that is accessible by files that call the module.
You have multiple packages within one file. In which case, you would need a global variable for something accessed by both packages. It would be rather unusual to do this, however.
It is pretty clear that you aren't doing either of those things, so you should just stick with my. If you do want to declare a global, the correct way to do so is with our. There are some important subtleties to that command, explained in the linked documentation.
You don't need to declare global variable in this case, local variable is enough. See example below.
if ( $cell->value() =~ /Site Name/ ) {
my $site_name_col = $col;
print $site_name_col;
}
OR
my $site_name_col = ''; # default value
if ( $cell->value() =~ /Site Name/ ) {
$site_name_col = $col;
}
print $site_name_col;

Directly changing an argument to a subroutine

It would make a lot of things easier in my script if I could use subroutines in the way that shift, push, and other built-in subroutines work: they can all directly change the variable that is passed to it without the need to return the change.
When I try to do this the variable is copied at some point and I appear to be simply changing the copy. I understand that this would be fine with references but it even happens with arrays and hashes, where I feel like I am simply passing the variable I was working on to the sub so that more work can be done on it:
#it = (10,11);
changeThis(#it);
print join(" ", #it),"\n"; #prints 10 11 but not 12
sub changeThis{
$_[2] = 12;
}
Is there a way to do this? I understand that it isn't best practice, but in my case it would be very convenient.
That's what prototypes are for:
#!/usr/bin/perl
use strict;
use warnings;
sub changeThis(\#); # the argument will be seen as an array ref (prototype must come before the call!)
my #it = (10,11);
changeThis #it; # even when called with an array
print join(" ", #it),"\n"; #prints 10 11 12
sub changeThis(\#)
{ my( $ar)= #_; $ar->[2]= 12; }
See http://perldoc.perl.org/perlsub.html#Prototypes for more information.
It's not really a popular method though, passing actual array references is probably a better alternative, with less magic involved.
The problem is that the sub call expands the variable to a list of values, which are passed on to the sub routine. I.e. a copy is passed, not the variable itself. Your sub call is equal to:
changeThis(11, 12);
If you wish to change the original array, pass a reference instead:
use strict;
use warnings;
my #it = (10,11);
changeThis(\#it);
print join(" ", #it),"\n";
sub changeThis{
my $array = shift;
$$array[2] = 12;
}
Also, #_[2] will give you the warning:
Scalar value #_[2] better written as $_[2]
If you use warnings, which of course you should. There is no good reason to not turn on warnings and strict, unless you know exactly what you are doing.
As the previous answers suggest, you should use a reference passed to the subroutine.
Additionally you also can use implicit referencing if you want to read trough the documentation for Prototypes
sub changeThis(\#);
#it = (10,11);
changeThis #it;
print join(" ", #it),"\n"; #prints 10 11 12
sub changeThis(\#){
$_[0][2] = 12;
}
(note that you either have to predeclare your subs before the first call or put the sub definitions on top.)