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

Hi Confreres,

I have a simple question!

What is the difference of (if there is one ...)
my $var; my $var = ""; my ($var); m ($var) = "";
or what is the best way to declare a variable?

Thanks

Murcia

edited: Tue Sep 2 15:16:58 2003 by jeffa - formatting, code tags

Replies are listed 'Best First'.
Re: declaration of variables
by davido (Cardinal) on Sep 02, 2003 at 07:31 UTC
    or what is the best way to declare a variable?

    I'll respond to that question first. The best way depends on what you're trying to accomplish, and the 'scope' you're trying to achieve.

    my declares variables to exist within the innermost block. In this sense, I mean block as a literal { } pair, or as a subroutine, or as a file, or even as an eval. What this means is that when you declare a variable with my, it lives within the block in which it was declared, and falls out of scope when the block itself passes from scope. It probably gets a little more complicated than that sometimes (if you make it), but generally just count on variables declared with 'my' as existing within the block in which they were declared. But that probably wasn't really your question.

    You were asking what is the difference between some of the commonly seen usages of 'my'. I'll try to respond accurately. I'm sure if I miss something we'll hear about it. ;)

    my $var; # Declares a single variable.

    The following example assigns the variable a value:

    my $var = "Hello world!\n"; my $var = 10; my $var = 0; my $var = ""; my $var = \@some_array; my $var = \%some_hash; my $var = \$some_scalar; my $var = \&some_function;

    In the preceeding examples, you're assigning $var some value. It is not always necessary to assign $var the value of "" (the null string). Unlike C, variables in Perl are already empty when you create them. But empty in this case means undefined. In the context of "What is false" and "What is true", undef, "" (null string), and 0, are all "false". But if you are counting on a null string, assign it as in your examples. Redundancy isn't always bad either; in some cases you'll want to assign something, even if it's nothing, to add clarity.

    What if you want to declare multiple variables? my binds more tightly than the comma, so you cannot just say, my $this, $that;. You must use paranthesis:

    my ( $this, $that );

    The parenthesis are also serving the dual function of (1) Specifying order of precedence so that the comma binds more closely than the my. And (2) the parenthesis have also created a list. That means you can legitimately do this:

    my ( $this, $that ) = ( "the", "other" );

    It is not wrong to say,

    my ($var);

    or

    my ($var) = "This";

    It's just not *necessary* in this situation to use the parens. ...but it doesn't hurt anything.

    Some additional things you can do:

    my ( $this, $that ) = "The other";

    Now $this has been assigned a value, and $that has not. ...and you can do this:

    my @array = ("This", "That", "and", "The", "Other"); my %hash = ( "This" => "That", "The" => "Other" ); my $var = ("This", "That"); # $var now contains "That". my ( $this, $that ) = \( $the, $other ); # The reference # constructer is distributive and # applies to both items inside the rvalue # list.

    And there are plenty of other things you can do. Just remember, if there is more than one variable on the left, use parenthesis so that 'my' binds to both. The rest you'll find behaves pretty much how you expect it to when you need it.

    Dave

    "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

      Dave, one point of clarification on this thread: how would you "clear" a variable that you are using over again and again, such as in a loop? See line 7:
      1: my $tempstring; 2: for $i (1...10) { 3: for $j (1...10) { 4: $tempstring .= $array[$j]; } 6: $final[$i] = $tempstring; 7: $tempstring = ""; }
      or would/could you use:
      7: my $tempstring;
      or
      7: undef $tempstring;
      or is that declaring it too many times? or is using undef has bad as I've read?

      Thanks, and I will acolyte for you anytime.
        I think this is a perfectly valid place to undefine a variable. You could also use my to redeclare the variable, but there is no need to declare the variable both inside the loop and outside:
        my @final; my @array = qw(foo bar baz); for (0..$#array) { my $temp; for my $j (0..$#array) { $temp .= $array[$j]; } push @final, $temp; }
        Remember, undef is not bad, you just have to know when it is a good choice:
        my $temp; for (0..$#array) { for my $j (0..$#array) { $temp .= $array[$j]; } push @final, $temp; undef $temp; }
        Here, it is perfectly fine because we are undefining a scalar. But, what happens if we push another array instead?
        for my $i (0..$#array) { my @temp = @array; push @final, \@temp; undef @temp; }
        This is a bad choice. Now @final contains three anonymous, empty array references. What happened? We copied the contents of @array, but after we pushed our temp array, we undefined it - hence, we 'erase' the data we just pushed. But, had we pushed a new anonymous array reference that contained our temp array, then it works:
        for my $i (0..$#array) { my @temp = @array; push @final, [@temp]; undef @temp; }

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
        If you wanted to let scoping clear the variable for you, you can do it like this:

        1: for $i (1..10) { 2: my $tempstring; 3: for $j (1..10) { 4: $tempstring .= $array[$j]; 5: } 6: $final[$i] = $tempstring; 7: }

        What that does, is that $tempstring is declared in the outter for block. Each time you iterate through the outter for block, $tempstring falls out of scope at the end of the block, and is re-introduced in the next iteration. Quite literally, even on the last iteration of the outter for block, once you leave the block behind, $tempstring is gone. I prefer this method because it ensures that temporary, or loop variables just disappear when I don't need them anymore.

        For that matter, if you no longer are going to be needing access to $i and $j, you can declare them with block scope as well:

        for my $i (1..10) {.......

        This will ensure that at the end of the looping those variables also disappear, rather than possibly clouding up some other portion of your code. This is the merit of scoping; limiting scope! That's a good thing. IMHO, variables should only exist within the relm of where they are needed.

        Dave

        "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

        The best answer to your question is to reverse lines 1 and 2, then omit line 7.

        But red flag alert!

        Any time you find yourself doing a lot of accessing a function by index, you are opening yourself up for potential looping bugs (off by one, fencepost, etc). As a sign of that I note that you are initializing your array by index in a loop that starts from 1. But Perl's arrays count by offset - the first index is always 0!

        Generally you can get rid of that source of error by letting Perl take care of the array accessing logic for you. (For those who have their priorities backwards, it is also marginally faster.)

        my @final; for my $i (1..10) { my $temp_string = ""; for my $x (@array) { $temp_string .= $x; } push @final, $tempstring; }
        Additional note. Note the my declaration on the loop variables? That is because I use strict.pm unless I have very good reason not to. (Free typo check! Why wouldn't I want that?) Hence I don't fall into any habits (such as not declaring loop variables) which conflict with that.
Re: declaration of variables
by liz (Monsignor) on Sep 02, 2003 at 08:13 UTC
    I think davido said it all in Re: declaration of variables, but he failed to comment on the last possibility that you mentioned.
    m ($var) = "";
    I have no idea where you got that from. The simplest explanation would be that it is a typo and that you in fact meant:
    my ($var) = "";
    If that is what you meant, read no further.















    You're reading further. Ok, what you wrote almost has meaning. But should probably only be used in obfuscations, never in real code.
    m ($var) = "";
    is basically equivalent with:
    $_ =~ m/$var/ = "";
    which of course is an error, namely:
    Can't modify pattern match (m//) in scalar assignment
    
    But had your example shown just:
    m ($var);
    that code would have compiled to:
    $_ =~ m/$var/;
    if you don't use use strict; (which you don't in your example). A scary thought.

    Therefore, once again, always use strict; (and use warnings; if you're using Perl 5.6.0 or later).

    Liz

    Update:
    Made a little clearer with what I meant with "It".

      (Update: Sorry for the confusion. Until Liz' update about the fact that she was talking about "m ($v) =..." in the second half of her reply, I mistook her reply to be talking about the ordinary "my ($v) = 'a';".)

      Hi Liz,
      I don't think "my ($v) = '';" is equivalent to "$_ =~ m/$var/ = '';" and throwing a warning.
      (cmd.exe has different shell quoting!) %perl -w -Mstrict -e "my ($v) = '';" (no warnings)
      And thus:
      %perl -w -Mstrict -e "my ($v) = 'a'; print $v;" a
      which parses in my head as 'string is assigned to first element of the left hand side list'. I can't argue with the exact concepts applied by the interpreter because I forgot most about the weirder rules of context including lvalue stuff. But this seems to support the above:
      %perl -w -Mstrict -e "my ($v,$s) = 'a'; print $v, $s;" aUse of uninitialized value in print at -e line 1.
      Still, string being assigned to first element of the left-hand side list. Same for lists on the right-hand side. (Which would be common usage in contrast to the above weirdness.)
      %perl -w -Mstrict -e "my ($v,$s) = ('a'); print $v, $s;" aUse of uninitialized value in print at -e line 1.
      Good. As expected. Same goes for two-element lists on the rhs.
      %perl -w -Mstrict -e "my ($v,$s) = ('a', 'b'); print $v, $s;" ab
      And the ',' operator has lower precedence than '=', so we get a 'useless use of a constant' error.
      %perl -w -Mstrict -e "my ($v,$s) = 'a', 'b'; print $v, $s;" Useless use of a constant in void context at -e line 1. aUse of uninitialized value in print at -e line 1.
      Hope this clarified things a little.
Re: declaration of variables
by wirrwarr (Monk) on Sep 02, 2003 at 07:04 UTC
    If you don't give a value to the variable, then its value is undefined, which is different from having the empty string as value.
    The list notation ($var) is normally used to declare several variables at once, like in
    my ($a, $b, $c) = (1, 2, 3);
    The first and third line in your text have the same effect, and the second and fourth line have the same effect.
    my $a; my $b = ""; print "\$a is not defined\n" unless defined $a; print "\$b is defined\n" if defined $b;


    daniel.