Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

declaring same variable

by samy1212 (Novice)
on Jan 20, 2004 at 17:12 UTC ( [id://322637]=perlquestion: print w/replies, xml ) Need Help??

samy1212 has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks , I am trying to declare a variable more than once but having problems :
my @xxx = (one, two, three) if ( $op eq "numbers" ); my @xxx = (four, five) if ( $op eq "alpha" ); my @xxx = (six, ten) if ( $op eq "alp" );
I am getting a warning of and earliear declartion . I am tryin to avoide using if statment. Can someone advice ? thanks

Replies are listed 'Best First'.
Re: declaring same variable
by markov (Scribe) on Jan 20, 2004 at 17:26 UTC

    "my @x if condition" is quite dangerous, because it creates a kind of global variable with restricted scope! If this is in a subroutine, the second time you call the sub, you get exactly the same array, not a new one.

    But anyway.. this switch-like initiation is very common, and I like to write it like this:

    my @xxx = $op eq 'numbers' ? (one, two, three)
            : $op eq 'alpha'   ? (four, five)
            : $op eq 'alp'     ? (six, ten)
            : die;   # or ()
    
    Just one of many ways to express the same.
      While that code snippet is correct, the first paragraph of explanation is actually partially wrong.

      .... it creates a kind of global variable with restricted scope! If this is in a subroutine, the second time you call the sub, you get exactly the same array, not a new one.

      This is not true. Look at the following:

      use strict; use warnings; sub mytest { my $var if 0; $var++; print $var, "\n"; } mytest(); mytest(); __OUTPUT__ 1 1

      We see several important things in that snippet. First, there are NO errors under strictures, and no warnings. Second, $var is NOT the same variable each time mytest() is called. If we had created a closure, the output would have been 1 and 2, not 1 and 1. If we had autovivified a global, we would have gotten a strictures error, or at minimum, the output would have been 1 and 2. But none of that happens. We get a new lexical variable each time mysub() is called.

      Why?

      Because my has two elements to how it works. First, the compiletime side. At compiletime, the framework is made for a lexical variable. Yet at compiletime, it is too soon to know the outcome of program logic. So the lexical is created without any regard for logic; all that matters is lexical scope.

      At runtime, logic springs to life. And if the "my" declaration has an assignment component to it, as in  my $x = 10 if $condition; that assignment will only take place if $condition is true. But $x exists within the lexical block whether or not $condition is ever true. And it falls out of scope just like any good lexical would, when the lexical block ends, even if its a subroutine.


      Dave

Re: declaring same variable
by b10m (Vicar) on Jan 20, 2004 at 17:17 UTC

    I don't know if it's considered the right way to do, but it'll take away the errors ;)

    my @xxx = (); @xxx = ("one", "two", "three") if ( $op eq "numbers" ); @xxx = ("four", "five") if ( $op eq "alpha" ); @xxx = ("six", "ten") if ( $op eq "alp" );
    --
    b10m
Re: declaring same variable
by Limbic~Region (Chancellor) on Jan 20, 2004 at 17:23 UTC
    samy1212,
    Perhaps your problem is with scoping. If that's the case, you should take a look at the Tutorials section, in particular:
  • Coping with Scoping off site
  • Variable Scoping in Perl: the basics

    When you declare a variable - you are not only declaring it's name (what follows the leading sigil), it's type (scalar, hash, array, typeglob, etc), you are also declaring it's scope. When you declare a variable with my, you are restricting its scope to the nearest enclosing curly braces.

    Probably what you want to do is change its current value and not actually declare it again:

    my @array = qw(1 2 3); @array = qw(one two three) if $op eq 'alpha';
    Conditionally declaring a variable is generally considered a bad idea and can lead to problems down the road. So your code would change to:
    my @xxx; @xxx = qw(one two three) if $op eq 'numbers'; @xxx = qw(four five) if $op eq 'alpha'; @xxx = qw(six ten) if $op eq 'alp';
    Finally, if you want to use the same variable name, but in different scopes - that is perfectly acceptable:
    #!/usr/bin/perl -w use strict; hello('world'); goodbye('world'); sub hello { my $greeting = shift; print "hello $greeting\n"; } sub goodbye { my $greeting = shift; print "goodbye $greeting\n"; }
    I hope this helps - L~R
Re: declaring same variable
by broquaint (Abbot) on Jan 20, 2004 at 17:18 UTC
    Just move the variable declaration above the first if modifier e.g
    my @xxx; @xxx = (one, two, three) if ( $op eq "numbers" ); @xxx = (four, five) if ( $op eq "alpha" ); @xxx = (six, ten) if ( $op eq "alp" );
    You'll no longer get the warning as you won't be declaring the @xxx multiple times (as lexicals are declared at compile-time (i.e when it's putting the program together)).
    HTH

    _________
    broquaint

Re: declaring same variable
by ysth (Canon) on Jan 20, 2004 at 18:32 UTC
    You need to distinguish between the concepts of "declaring" a lexical variable (using "my" to let the compiler know about it) and initializing or setting it. While you can do both in one statement, there is no need to (and if the assignment is conditional there may be need not to).

    Just declare the variable first (my @xxx;) and then set it in a separate statement (just the way you have it is fine, once the my's are removed and a my @xxx; added at the top).

    The warning you got should alert you that each time you say my @xxx, you are creating a new variable named @xxx and hiding the old one: almost certainly not what you want.

    Others have warned you of the evils of my whatever if condition;   perldoc perlsyn says:

    NOTE: The behaviour of a my statement modified with a statement modifier conditional or loop construct (e.g. my $x if ...) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.
      thanks to all for the help
Re: declaring same variable
by aging acolyte (Pilgrim) on Jan 20, 2004 at 17:22 UTC
    Just declare my @xxx once.

    my $op = "numbers"; # for example my @xxx = qw(one two three) if ( $op eq "numbers" ); @xxx = qw(four five) if ( $op eq "alpha" ); @xxx = qw(six ten) if ( $op eq "alp" ); print "@xxx\n";
    results in: one two three

    A.A.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://322637]
Approved by aging acolyte
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (7)
As of 2024-04-12 11:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found