local and my variables in a subroutine

P

Phil Jacobson

Good afternoon, I was fooling around with the following test code:

1. sub pageprint
2. {
3. foreach my $one (@pages)
4. {
5. my @subpage = @{$one};
6. foreach my $two (@subpage)
7. { print "$two\n"; }
8. }
9. }
10.
11. my @page1 = ("1", "2", "3");
12. my @page2 = ("one", "two", "three");
13. my @page3 = ("uno", "dos", "tres");
14. my @pages = (\@page1, \@page2, \@page3,);
15. &pageprint;

The above code doesn't work unless I remove the "my" declarations. It
brought up a few questions: Does the interpreter create a @pages when
it sees line 3 and then creates another separate one when it sees line
14? I understand if I put the subroutine at the bottom of the code it
will work with all the arrays my'd. The code also works having the
subroutine first if I "local" the page arrays. Are there any benefits
I'm overlooking of having Perl operate this way and in your opinion,
what are some of the best ways to deal with a situation where you want
to handle global variables inside a subroutine?

Thank you for your time,
Phil Jacobson
 
D

Darren Dunham

Phil Jacobson said:
Good afternoon, I was fooling around with the following test code:
1. sub pageprint
2. {
3. foreach my $one (@pages)
4. {
5. my @subpage = @{$one};
6. foreach my $two (@subpage)
7. { print "$two\n"; }
8. }
9. }
10.
11. my @page1 = ("1", "2", "3");
12. my @page2 = ("one", "two", "three");
13. my @page3 = ("uno", "dos", "tres");
14. my @pages = (\@page1, \@page2, \@page3,);
15. &pageprint;
The above code doesn't work unless I remove the "my" declarations.

Which ones? The only problem I had was that you used a variable
(@pages) on line 3 without declaring it elsewhere. If you had a 'use
strict', then this code would not compile.

If you didn't use strict, but had warnings enabled, it would tell you..

Name "main::pages" used only once: possible typo at perl line 3.

Which should give you a clue as to what is happening. Why don't you
have warnings enabled when you're working with new code?

Also, what do you mean by "doesn't work"? Does it fail to compile or is
the output not what you expect?

I put a 'my @pages' above the subroutine, and then changed line 14 to be
simply 'pages = ....'

Without that, then the @pages you're assigning in line 14 and the @pages
you're using in line 3 are different variables.
It brought up a few questions: Does the interpreter create a @pages
when it sees line 3 and then creates another separate one when it sees
line 14?

I wouldn't use the verb 'create' here, but yes, those are two separate
variables. Since prior to line 3, no 'my @pages' is seen, then the one
there is the package variable main::pages. Later on line 14 you declare
a new lexical variable and assign to it.
I understand if I put the subroutine at the bottom of the code it
will work with all the arrays my'd.

That's because the '@pages' in the subroutine would be after the lexical
declaration of 'my @pages' and would share the scope.
The code also works having the
subroutine first if I "local" the page arrays. Are there any benefits
I'm overlooking of having Perl operate this way and in your opinion,
what are some of the best ways to deal with a situation where you want
to handle global variables inside a subroutine?

I think you need to understand why your code is not working, and how
lexical variables work before you try to understand 'local'. It has
it's uses, but I would not consider it in this situation.
 
A

A. Sinan Unur

(e-mail address removed) (Phil Jacobson) wrote in
Good afternoon, I was fooling around with the following test code:

Please

use strict;
use warnings;

in code you post here. Also,

use diagnostics;

may help.
1. sub pageprint
2. {
3. foreach my $one (@pages)
4. {
5. my @subpage = @{$one};
6. foreach my $two (@subpage)
7. { print "$two\n"; }
8. }
9. }
10.
11. my @page1 = ("1", "2", "3");
12. my @page2 = ("one", "two", "three");
13. my @page3 = ("uno", "dos", "tres");
14. my @pages = (\@page1, \@page2, \@page3,); ....

The above code doesn't work unless I remove the "my" declarations. It
brought up a few questions: Does the interpreter create a @pages when
it sees line 3 and then creates another separate one when it sees line
14?

That question would have been answered for you had you enabled strictures
and warnings in your code.
15. &pageprint;

Make sure the behavior implied by this syntax is the behavior you want.

what are some of the best ways to deal with a situation where you want
to handle global variables inside a subroutine?

I don't know what is best in that case, but in my opinion, the following
code is preferable:

use strict;
use warnings;

my @page1 = ( '1', '2', '3');
my @page2 = ('one', 'two', 'three');
my @page3 = ('uno', 'dos', 'tres');

pageprint(\@page1, \@page2, \@page3);

sub pageprint {
foreach (@_) {
foreach (@{$_}) {
print "$_\n";
}
}
}
 
B

Bob Walton

Phil said:
Good afternoon, I was fooling around with the following test code:

1. sub pageprint
2. {
3. foreach my $one (@pages)
4. {
5. my @subpage = @{$one};
6. foreach my $two (@subpage)
7. { print "$two\n"; }
8. }
9. }
10.
11. my @page1 = ("1", "2", "3");
12. my @page2 = ("one", "two", "three");
13. my @page3 = ("uno", "dos", "tres");
14. my @pages = (\@page1, \@page2, \@page3,);
15. &pageprint;

The above code doesn't work unless I remove the "my" declarations. It
brought up a few questions: Does the interpreter create a @pages when
it sees line 3 and then creates another separate one when it sees line
14? I understand if I put the subroutine at the bottom of the code it
will work with all the arrays my'd. The code also works having the
subroutine first if I "local" the page arrays. Are there any benefits
I'm overlooking of having Perl operate this way and in your opinion,
what are some of the best ways to deal with a situation where you want
to handle global variables inside a subroutine?
....


Phil Jacobson

Try putting your sub after the main program code. Then it will work
fine. Note that it is necessary to declare a variable the first time
the compiler encounters it, and that, in a case like you give here, it
also matters whether the declaration is in the main program or the sub.
Also, add:

use strict;
use warnings;

to the start of your program -- let Perl help you all it can.

You could also add:

my @pages;

at the start of your program and delete the "my" in front of
"my @pages = (..."

Note, though, that it is not really good practice to use a lexical
declared with my() as if it were a package global variable -- it might
be considered misleading. In any event, the variable needs to be
declared the first time the compiler encounters it, unless it is
actually a package global (Perl's default variable type) -- and in that
case, it must be withheld from "use strict"'s effects via a "use vars"
declaration.

Also note that the usual way of getting variables to a sub is to pass
them as arguments (in the case of arrays or hashes, a reference to the
variable is passed). This will generate "pure" subs that don't generate
side-effects, which is helpful when others need to deal with your
program. Good programmers would usually consider good subs to be pure
subs. Using package globals (or even lexical variables defined in the
scope of the sub definition) to pass values to a sub is an invitation
for bugs and hard-to-debug code. This doesn't mean it is wrong --
sometimes it is just the ticket (as with closures). It probably
warrants commentary when used.

And finally, the &subname call to a sub is generally frowned upon these
days (see "perldoc -q &foo"). The & does a couple of things it is very
possible you might not realize, and, unless you specifically want those
things, can get you into trouble in a fashion that will be hard to debug
if you aren't aware.

HTH.
 
J

Jay Tilton

: Note, though, that it is not really good practice to use a lexical
: declared with my() as if it were a package global variable

Says who? This sounds like you're peddling a style choice as a programming
axiom.

: it might be considered misleading.

By whom? What misapprehension could it cause?

In my own code, declaring a file-scoped lexical visibly identifies it as
something the external world doesn't need to know and shouldn't muck around
with. Package variables are reserved for information that the external
world might need to know or change.
 

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

No members online now.

Forum statistics

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

Latest Threads

Top