0

My code is:

my $r = ['111','222','aaa','bbb'];
print $r;
my $s = ('111','222','aaa','bbb');
print $s;

The first print I can understand, $r would be a ref and print gives me something like ARRAY(0x44444444).

But I cannot understand why the second example, print $s gives me the last element, bbb, but why?

brian d foy
  • 129,424
  • 31
  • 207
  • 592
fgg1991
  • 65
  • 8
  • `$s='111'; $s='222'; $s='aaa'; $s='bbb' ` at final the `$s` value is `bbb`. see the user `@amon` answer. And if you assign the array(not list) in a scalar it will return the number of element – mkHun Sep 26 '17 at 10:30
  • 1
    There is no array in your second example. That is a list. [Arrays are not lists](http://friedo.com/blog/2013/07/arrays-vs-lists-in-perl). – Dave Cross Sep 26 '17 at 11:27
  • 1
    @Dave Cross, What the OP has (comma operator in scalar context) and what the link calls a list (comma operator in list context) are not the same thing. – ikegami Sep 26 '17 at 15:08
  • @ikegami: Even in the final section, "Arrays may be used in scalar context", which, to me, seems to cover exactly this case? – Dave Cross Sep 26 '17 at 15:11
  • 1
    @Dave Cross, oh how nice; they're not even consistent with their definition of list. Yay for adding to the confusion while pretending to try to clear it up! – ikegami Sep 26 '17 at 15:14
  • @ikegami: Seems consistent to me. He says "Although what we wrote *looks* like a list, lists *do not exist* in scalar context". Perhaps you could be clearer about exactly what you're objecting to. – Dave Cross Sep 26 '17 at 15:18
  • 1
    They describe a number of things that apply to "list", then use three different definitions of list in the document. – ikegami Sep 26 '17 at 15:19
  • @ikegami: Honestly, I really don't see what you're objecting to. I often use that blog post as the best (or, at least, most understandable) explanation of the difference between arrays and lists. If you have a better article that I could use, I would happily switch to it. – Dave Cross Sep 26 '17 at 15:24
  • 1
    @Dave Cross, There's so much wrong with it, I don't even know where to begin. Even with the leading table... Lists are ephemeral, distribute references and don't exist in scalar context? WRONG! List values are ephemeral and they can't possibly distribute reference or exist in any contxet since they aren't code; and list operators distribute references, can exist in scalar context and aren't ephemeral. – ikegami Sep 26 '17 at 15:27
  • @Dave Cross, As for a better reference, I don't know what references exist. – ikegami Sep 26 '17 at 15:33
  • 1
    @Dave Cross, I bet you think `(4,5,6)` creates a list in `@a = (4,5,6)`. If so, that article has failed you. – ikegami Sep 26 '17 at 15:47
  • The better reference is in the perl docs https://perldoc.perl.org/perlfaq4#What-is-the-difference-between-a-list-and-an-array? One of the weird things about explaining this concept is the value the expression gives you. Since the size of `(1, 2, 3)` is three, and assigning that to a scalar yields `3`, it's the same as assigning to a scalar an array of the same list. That's why I did something different in the perlfaq4 answer. – brian d foy Jul 09 '23 at 15:45

3 Answers3

6

The function of the comma operator , depends on the context. There is list context and scalar context to consider.

In list context, the comma operator separates items in a list. An assignment imposes list context on the right hand side if the left side is an array or is enclosed in parens:

my ($s) = (1, 2, 3);  #=> $s = 1, rest discarded
(my $s) = (1, 2, 3);  # the same
my @arr = (1, 2, 3);  #=> @arr = (1, 2, 3)

In scalar context Perl expects us to provide a single value. The comma operator then works just like in C or other languages: all expressions are evaluated and their value discarded. Only the last value is kept:

my $s = (1, 2, 3);  #=> $s = 3, previous items discarded

See also: the Comma Operator in perldoc perlop

Note that the parens (...) do not create an array. They are only used to control precedence. In $s = (1, 2, 3) the arrays are needed because $s = 1, 2, 3 would be parsed as ($s = 1), 2, 3.

amon
  • 57,091
  • 2
  • 89
  • 149
  • Oh thank you very much ! Obviously I didn't distinguish array and list well. So something like qw/aaa bbb ccc/ or ('aaa', 'bbb', 'ccc') are just lists but @_ is an array right ? – fgg1991 Sep 27 '17 at 01:20
  • @fgg1991 Yes, arrays must always be named variables or array references. Perl does not have array literals. Lists are the opposite: lists don't really exist as a data structure. It is better to think of them as part of the syntax or evaluation model. – amon Sep 27 '17 at 06:19
  • 1
    See https://perldoc.perl.org/perlfaq4#What-is-the-difference-between-a-list-and-an-array? One of the weird things about explaining this concept is the value the expression gives you. Since the size of `(1, 2, 3)` is three, and assigning that to a scalar yields `3`, it's the same as assigning to a scalar an array of the same list. That's why I did something different in the perlfaq4 answer. – brian d foy Jul 09 '23 at 15:42
2

There are a couple things going on here, most of which is covered in Intermediate Perl.

First, the [] braces makes an array reference, and all references are scalars. Assigning a reference to a scalar is assigning a scalar to a scalar. When you output this, you see the stringification of a reference: ARRAY(0x44444444). Whenever you give something to print, it stringifies itself by whatever rules that thing uses: references show their type and an internal (not physical) memory address.

Second, Perl decides how to treat the righthand side of an assignment based on what it sees in the lefthand side. In both assignments you have a scalar on the left, so Perl picks scalar semantics. In general, Perl cares more about the "verbs" than the "nouns", which is a switch from many mainstream languages which choose their operations based on what you have (the particular object identity) instead of what you are doing with it.

The tricky part here is that many people never took the time to figure out the difference between an array and a list, so there are a lot of terrible explanations out there.

So, what is this?

('111','222','aaa','bbb')

In Perl, we don't know yet because we don't have context. In human terms, that looks like a list. It has several items, it has parens around it, and outside of programming, that's what we call a list. But this is not outside of programming, and every language is very particular about some ideas such that our everyday uses of that idea doesn't translate. (Which is one of the strongest arguments to go through a tutorial for any language, not just to learn its syntax but also its basic concept).

But, back to that Perl expression, ('111','222','aaa','bbb'). It's floating in the ether waiting for something to give it the extra context it needs.

Inside a foreach, Perl uses list context because that's what foreach does:

foreach my $item ( ('111','222','aaa','bbb') ) { ... } 

Assigning to an array enforces a list context, because that's what it does:

 my @array = ('111','222','aaa','bbb');

Creating an array reference is the same:

 [ ('111','222','aaa','bbb') ]

In Perl, you have to know which context you have. That's a bit weird at first, but you get used to it.

Now, there are some things that don't use list context, and you've discovered one of those. Assigning this expression to a scalar uses scalar context, because that's what the assignment operator does when the lefthand side is a scalar:

my $s = ('111','222','aaa','bbb');  # not a list!

What does Perl do with the comma in scalar context? It does the same thing that C comma operator does. It evaluates the leftmost expression, discards the result, evaluates the righthand expression, and returns the result. In the case of several commas, that righthand result becomes the lefthand expression for the next comma. Ultimately, you end up with the evaluated expression at the end of the series.

In this example this seems silly, but consider something more complicated. Each of those sub-expressions may have side effects. In this example, each sub-expression sets the value of an existing variable:

use v5.10;

my( $dog, $cat, $bird );
say join "\n", "---Start", "Dog: $dog", "Cat: $cat", "Bird: $bird";

my $s = ( $dog = 'Snoopy',  $cat = 'Garfield', $bird = 'Woody' );
say join "\n", "---End", "Dog: $dog", "Cat: $cat", "Bird: $bird";
say "\ns is $s";

The output shows that the variables get new values as a result of the comma operator in scalar context, and that the final value of $s is the last evaluated expression in the series:

---Start
Dog:
Cat:
Bird:
---End
Dog: Snoopy
Cat: Garfield
Bird: Woody

s is Woody

This is useful in some places where Perl expects a scalar. Consider a C-style for loop where you iterate over a single variable, and each of the three places in the construct deal with one variable. Any of those places can have side effects, that but this is how it's typically written:

for( $i = 0; $i <= 137; $i++ ) { ... }

You could also use the scalar comma to have multiple side effects in the initialization and increment sections. This is sometimes useful, especially when the block can skip or adjust the parameters:

for( $i = 0, $j = 0; $i + $j <= 137; $i++, $j++ ) { ... }

Some advice on answers

A typical answer uses the example expression (1, 2, 3) because that's a natural one. However, it comes with an unintended confusion because it evaluates to the same thing either way, but for different reasons:

my @array = ( 1, 2, 3 );
my $s = @array;   # size of array, 3

Assigning that expression to a scalar also gets 3, because that's the last thing in the series:

my $size = ( 1, 2, 3 );  # scalar comma

It's better to choose a different example so the number 3 isn't accidently the result. It would be better if the size was not an element in the array, and even better if the scalar result would not be a number. The original question did that:

('111','222','aaa','bbb');

The other answers, however, fell for this trap.

In general, for examples, choosing non-sequential or unrelated answers can elucidate the mechanics.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
-1

When you assign a array to Scalar variable, Variable gets assigned with size of an array. Value should be 9.

@Array = (1,2,3,2,3,4,5,1,2);
$ScalarValue = @Array;
print("Scalar Variable should print, size of an array $ScalarValue);
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 14 '23 at 21:10