37

I sometimes see Perl code like this:

my ( $variable ) = blah....

What is the point of putting parentheses around a single variable? I thought parentheses were only used when declaring multiple variables, like:

my ( $var1, $var2, $var3 ) = blah...
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
phileas fogg
  • 1,905
  • 7
  • 28
  • 43
  • 2
    it might be helpful for maintenance, if it is apparent that a list might be the future expectation. I normally use it while reading subroutine arguments, like `my ($arg1) = @_` rather than `my $arg1 = shift` – Unos Apr 05 '12 at 15:34
  • I'm just used to typing `m y (`. And, a list of one item is still a list. :) – brian d foy Apr 05 '12 at 21:21

5 Answers5

47

There are several scenarios when there is a difference:

  1. When array is on right side

    my @array = ('a', 'b', 'c');
    my  $variable  = @array;           #  3   size of @array
    my ($variable) = @array;           # 'a'  $array[0]
    
  2. When list is on right side

    my  $variable  = qw/ a b c d /;    # 'd'  last  item of the list
    my ($variable) = qw/ a b c d /;    # 'a'  first item of the list
    
  3. Subroutine with variable (array/scalar) return value

    sub myFunction {
      ...
      return (wantarray() ? @array : $scalar);
    }
    my  $variable  = myFunction(...);  # $scalar   from the subroutine
    my ($variable) = myFunction(...);  # $array[0] from the subroutine
    
Ωmega
  • 42,614
  • 34
  • 134
  • 203
21

The parentheses create a list context which affects how the right hand side of the assignment is evaluated.

Compare

my $x = grep { /s/ } qw(apples bananas cherries);
print $x;

with

my ($x) = grep { /s/ } qw(apples bananas cherries);
print $x;

You will often use this construction when you just want to grab the first element of a list and discard the rest.

Community
  • 1
  • 1
mob
  • 117,087
  • 18
  • 149
  • 283
  • Technically, it affects how both sides of the assignment operator is evaluated (by changing which assignment operator is used). – ikegami Apr 05 '12 at 20:10
7

I'm not a Perl pro (by all means, I'm not), but AFAIK it has to do with lists. Perl has different contexts (scalar, list). Using ($var) switches to list context, $var is scalar context.

my $var = (1, 2, 4);   # $var = 4 (last element)
my ($var) = (1, 2, 4); # $var = 1
E_net4
  • 27,810
  • 13
  • 101
  • 139
knittl
  • 246,190
  • 53
  • 318
  • 364
  • You're right, and `$var = grep {; defined } (1, 2, 4);` = 3 (items) – Axeman Apr 05 '12 at 17:20
  • Also `my @a = (1,2,4); my $v = @a; print $v;` = 3 – knittl Apr 05 '12 at 17:30
  • However `$var = (1, 2, 4)` assigns 4 to `$var`. `grep` behaves in a specific way depending on its context, and in scalar context it provides the number of list elements that pass the test. That is different from the behaviour of a list in scalar context. – Borodin Apr 05 '12 at 18:31
  • @Borodin: yes, like I wrote in my answer – knittl Apr 05 '12 at 19:27
  • No not like you wrote in your answer. In scalar context `(1,2,4)` is not a list but an expression with the comma operator that returns it's right hand side and discards it's left hand side. Resulting in 4 being returned – matthias krull Apr 05 '12 at 19:50
  • @mugenkenichi: »However $var = (1, 2, 4) assigns 4 to $var.« … I have written the same statement in my answer. Yes, I have explained it has to do with lists, but the code is the same. (I will update my answer now) – knittl Apr 05 '12 at 19:58
  • It might seem picky but it is just not a good example to show what you mean.. it has to with context not with lists. It is a tricky one though. Your first comment is a good example. – matthias krull Apr 05 '12 at 20:07
  • This could be of help understanding why `my $var = (1,2,4)` is not a good example.. there is no list nor list context in this line: http://stackoverflow.com/questions/5042436/and-operators-in-perl/5043214#5043214 – matthias krull Apr 05 '12 at 20:13
  • 1
    [perlfaq4: What is the difference between a list and an array?](http://perldoc.perl.org/perlfaq4.html#What-is-the-difference-between-a-list-and-an-array%3f) – brian d foy Apr 05 '12 at 21:22
  • ***FYI*** `my @array = (1,2,4); my $var = @array` will result in `$var` containing `3`, which is the number of elements in the array. ( `my $var = @{[1,2,4]}` does the same thing ) Whereas `my ($var) = @array` will result in `$var` containing the first element of `@array`. – Brad Gilbert Apr 06 '12 at 06:56
7

You are confusing two different things. First off, when using my to declare several variables, you need to use parentheses:

my $foo, $bar;  

Does not work, as it is considered to be two different statements:

my $foo;
$bar;

So you need parentheses to group together the argument into an argument list to the function my:

my($foo, $bar);

Secondly, you have explicit grouping in order to invoke list context:

$foo, $bar = "a", "b"; # wrong!

Will be considered three separate statements:

$foo;
$bar = "a";
"b";

But if you use parentheses to group $foo and $bar into a list, the assignment operator will use a list context:

($foo, $bar) = ("a", "b");

Curiously, if you remove the RHS parentheses, you will also experience a hickup:

($foo, $bar) = "a", "b"; # Useless use of a constant (b) in void context

But that is because the = operator has higher precedence than comma ,, which you can see in perlop. If you try:

my @array = ("a", "b");
($foo, $bar) = @array;

You will get the desired behaviour without parentheses.

Now to complete the circle, lets remove the list context in the above and see what happens:

my @array = ("a", "b");
$foo = @array;
print $foo;

This prints 2, because the array is evaluated in scalar context, and arrays in scalar context return the number of elements they contain. In this case, it is 2.

Hence, statements such as these use list context:

my ($foo) = @array;          # $foo is set to $array[0], first array element
my ($bar) = ("a", "b", "c"); # $bar is set to "a", first list element

It is a way of overriding the scalar context which is implied in scalar assignment. For comparison, these assignments are in scalar context:

my $foo = @array;            # $foo is set to the number of elements in the array
my $bar = ("a", "b", "c");   # $bar is set to "c", last list element
TLP
  • 66,756
  • 10
  • 92
  • 149
  • Interestingly enough, `my $foo = ("a", "b"); print $foo;` will print `b`, and not `2` – knittl Apr 05 '12 at 16:07
  • @knittl Not as interesting as it sounds, because only *arrays* have that behaviour, not lists. In scalar context, lists return their last element instead. – TLP Apr 05 '12 at 16:09
  • 1
    [perlfaq4: What is the difference between a list and an array?](http://perldoc.perl.org/perlfaq4.html#What-is-the-difference-between-a-list-and-an-array%3f) – brian d foy Apr 05 '12 at 21:24
  • There's really no such thing as a list in scalar context. There's just scalars separated by the scalar version of the comma operator. It's as much a list as `$a && $b && $c`. – brian d foy Apr 05 '12 at 21:25
  • @brian d foy, `$x=(4,5,6);` has a list in scalar context. Notice the "s" that follows "list" in `perl -MO=Concise -e'$x=(4,5,6);'` The list/comma operator is not a binary operator like `&&`. – ikegami Apr 05 '12 at 22:58
  • From perlfunc: "You can't get a list like (1,2,3) into being in scalar context, because the compiler knows the context at compile time. It would generate the scalar comma operator there, not the list construction version of the comma. That means it was never a list to start with." – brian d foy Apr 06 '12 at 00:29
  • This answer doesn't show why you would use `my ($var) = @array;` instead of `my $var = @array;`. ( Which was the whole point of the question. ) – Brad Gilbert Apr 06 '12 at 08:19
  • @brian d foy, That simply says that lists (value) can't be *returned* in scalar context. A list (operator) can still exist in scalar context, though. As for "scalar comma operator", it's just another name for "comma operator", which is just another name for the "list operator". Did you run the code I gave you? What Perl actually does trumps any docs that say otherwise – ikegami Apr 06 '12 at 11:05
  • @BradGilbert I explicitly explain the difference between using list and scalar context when using an array in the RHS. I don't know what you are referring to. – TLP Apr 06 '12 at 13:45
  • You didn't put `my ($foo)` anywhere in your answer. That is what the question was about. It is a way of getting only the [first element of a list](http://stackoverflow.com/a/3728386) while also defining a variable. – Brad Gilbert Apr 06 '12 at 15:07
  • @BradGilbert Well, I explain the basic concepts. What you are referring to, and the specific question are only extensions of those basic concepts. – TLP Apr 06 '12 at 15:32
  • @BradGilbert I have updated with a conclusion, is this what you meant? – TLP Apr 06 '12 at 15:40
  • ***+1*** ... The only thing I would consider adding, is that it causes a subroutine to be called in list context. – Brad Gilbert Apr 06 '12 at 15:47
  • @BradGilbert That would be another extension of a basic concept. You have to draw the line somewhere, my answer is already very long. – TLP Apr 06 '12 at 15:52
  • Your answer is short in comparison to some of my most up-voted answers. ( I didn't say I would add it, only that I would have *considered* adding it ) – Brad Gilbert Apr 06 '12 at 16:04
2

[This answer is also found in table format here.]

The symbol = is compiled into one of two assignment operators:

  • A list assignment operator (aassign) is used if the left-hand side (LHS) of a = is some kind of aggregate.
  • A scalar assignment operator (sassign) is used otherwise.

The following are considered to be aggregates:

  • Any expression in parentheses (e.g. (...))
  • An array (e.g. @array)
  • An array slice (e.g. @array[...])
  • A hash (e.g. %hash)
  • A hash slice (e.g. @hash{...})
  • Any of the above preceded by my, our or local

There are two differences between the operators.

Context of Operands

The two operators differ in the context in which their operands are evaluated.

  • The scalar assignment evaluates both of its operands in scalar context.

      # @array evaluated in scalar context.
      my $count = @array;
    
  • The list assignment evaluates both of its operands in list context.

      # @array evaluated in list context.
      my @copy = @array;
    

      # @array evaluated in list context.
      my ($first) = @array;
    

Value(s) Returned

The two operators differ in what they return.

  • The scalar assignment ...

    • ... in scalar context evaluates to its LHS as an lvalue.

        # The s/// operates on $copy.
        (my $copy = $str) =~ s/\\/\\\\/g;
      
    • ... in list context evaluates to its LHS as an lvalue.

        # Prints $x.
        print($x = $y);
      
  • The list assignment ...

    • ... in scalar context evaluates to the number of scalars returned by its RHS.

        # Only dies if f() returns an empty list.
        # This does not die if f() returns a
        # false scalar like zero or undef.
        my ($x) = f() or die;
      

        # $counts gets the number of scalars returns by f().
        my $count = () = f();
      
    • ... in list context evaluates to the scalars returned by its LHS as lvalues.

        # Prints @x.
        print(@x = @y);
      
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 2
    Apparently someone does have a problem with offsite linking to documentation. I usually recommend to add a summary to your answer. – Brad Gilbert Apr 06 '12 at 08:23
  • @Brad Gilbert, Repeating what was already said 4 times is not a good thing as far as I'm concerned. – ikegami Apr 06 '12 at 11:08
  • If you look at all of the link-only answers on StackOverflow ( including deleted ones ) you'll find that a significant number of them are dead links. If your link pointed somewhere that hasn't been around as long as long as [Perl Monks](http://perlmonks.org), I would probably have down-voted it as well. Also there are several ways to get around the lack of tables. – Brad Gilbert Apr 06 '12 at 14:55
  • 1
    @Brad Gilbert, Yes, but I did link to a site that has been around as long as PerlMonks. – ikegami Apr 06 '12 at 21:25
  • 2
    I was pointing out that [*Link-Only* answers](http://meta.stackoverflow.com/search?q=link+only) are [**very much discouraged**](http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers) on Stack Overflow. – Brad Gilbert Apr 13 '12 at 19:20
  • @Brad Gilbert, You should read your own link. (Is that a subtle point? If so, I don't see how it applies.) I did not provide directions towards the answer, I provide directions to the answer; the OP knew exactly what he was clicking into; and Bitrot is not a factor. Furthermore, that very post argues that I should have linked. (SO should be treated like email, it argues, and there's no way a complex HTML page should be sent in an email.) – ikegami Apr 13 '12 at 19:33
  • @Brad Gilbert, I asked the question because the downvotes were downright hypocritical. The "exact duplicate" links posted here a gazillion times a day are the real violatiors of acceptability. Not only are the linked pages not even close to being "exact duplicates", they are frequently not even in the same ballpark. Combined with the resulting question closure, the petitioner is left without an answer. In this case, the OP go a clear, good answer that he could not have gotten otherwise due to SO limitations. – ikegami Apr 13 '12 at 19:45
  • I don't see how down-votes on this answer can be hypocritical, unless you are certain that the people who down-voted have posted answers that are link-only answers, and that is the only reason they down-voted. ... As for exact duplicates, edit them to differentiate them, and vote to open. Most of the questions that were incorrectly closed as "*Exact Duplicate*", should still have been closed, but for other reasons. If you really have a problem with how the site is run, you should be active on [Meta](http://meta.stackoverflow.com). – Brad Gilbert Apr 13 '12 at 22:05
  • @Brad Gilbert, I said downvoting a great answer because it's accessible through a link while closing nodes to replace them with a link to a useless "answer" is hyprocitical. And how can I edit a node to differentiate it when it's already different? – ikegami Apr 14 '12 at 03:07
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/33071491) – PeterJ Nov 01 '22 at 03:19
  • @PeterJ, The answer was added to this site [here](https://stackoverflow.com/a/54564429/589924) long ago, but it's not nearly as readable. I have replaced the text of my answer with the text of that answer. Now *this* is the answer that might become out of date. – ikegami Nov 01 '22 at 04:16