http://www.perlmonks.org?node_id=1035710

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

I apologize if this question has already been asked before... I'm new to perl and am trying to wrap my head around everything that can be done with the different variable types. So I wrote this and can't figure out what's going on. I made comments in the code where I'm confused.

#!/usr/bin/perl use strict; use warnings; my @arry = (); my ($one, $two, $three); $one = 1; $two = 2; $three = 3; @arry = ( $one, $two, $three ); print "two is $two \n"; $arry[1]++; print "two is $two \n"; #I'm expecting this to be 3, but it's 2 print join("\n", @arry), "\n"; #Output: >two is 2 >two is 2 >1 >3 #arry[1] = 3. Why doesn't print "$two" = 3? >3

Replies are listed 'Best First'.
Re: Array of variables
by Laurent_R (Canon) on May 28, 2013 at 21:28 UTC

    I am afraid that talking about references is taking the OP far too much forward at this point. It seems to me that the question is much more basic

    To the OP: when you assign the array this way:

    @arry = ( $one, $two, $three );

    Your are not putting these three variables into the array. You are putting into the array a copy of the current value of these variables at the time you do the assignment. So that, after this assignment, you array does not contain $one, $two and $three, but just their value, i.e. 1, 2 and 3.

    If you modify any of the three variables afterwards, this will not modify the elements of the array.

    Just to give another simpler example of the same thing:

    my $c = 3; my $d = $c; $c = 4; print "$d \n"; # prints 3

    On the second line, $d is assigned the value of $c at the time of the assignment, i.e. 3. $d is now a copy of the value of $c at the time of the assignment. Next line, $c is modified to 4. But this has no impact on $d, which has been given the value 3. This is exactly the same thing with your array.

    This is very basic programming. If a variable is assigned to another variable, it takes the value of the variable that is current at the time of the assignment. Modifying later the other variable has no impact on the first variable.

    You will learn later that it is possible to have the behavior that you were sort of expecting, this is what references are all about, but this is a more advanced topic that you probably don't want to study right now.

      This is a very good explanation! I was having a hard time figuring out what was going on here.

      Thank you all for the help!

      It's good to know though, that an object is a reference. This means that if $a is an object and you evaluate $b = $a; then both variables point to the same object and $a->Foo() is equivalent to $b->Foo();. Changing the value of $a doesn't change the value of $b though so if you later evaluate $a = new SomeObject('whatever'); then $a will refer to a different object than $b and $a->Foo() will no longer be equivalent to $b->Foo()!

      Even if you do not use references and complex data structures yourself, it's good to understand this.

      Jenda
      Enoch was right!
      Enjoy the last years of Rome.

Re: Array of variables
by davido (Cardinal) on May 28, 2013 at 20:00 UTC

    This line:

    @arry = ( $one, $two, $three );

    ...is creating a copy of the values stored in $one, $two, and $three. But they're just copies; the variables are in no way linked to the array itself.

    You probably want to pass references to $one, $two, and $three. That way @arry would hold references to those variables, not copies of their contents:

    @arry = ( \$one, \$two, \$three ); ${$arry[1]}++; # Increment the referent's value. print "two is $two\n"; print '$arry[1] is: ', $arry[1], "\n"; print '${$arry[1]} is: ', ${$arry[1]}, "\n";

    See perlref, but first perlreftut.


    Dave

      Ok, I'm confused....
      perl -le '($x, $y, $z) = (1, 2, 3); @a = ($x, $y, $z); print join ( " +", map { $_++, $_ } @a )' __output__ 1 2 2 3 3 4
      ...or more (which I believe) is more similar to the OP's example:
      perl -le 'my @a; my ($x, $y, $z) = (1, 2, 3); @a = ($x, $y, $z); print + $a[1]; $a[1]++, print $a[1];' __output__ 2 3
      Am I not breaking it correctly? :)
        What part of what you wrote are you confused about?
Re: Array of variables
by Jenda (Abbot) on May 29, 2013 at 09:37 UTC

    There are two places in Perl that may confuse people to think arrays contain variables. While @array = ($one, $two, $three); does make copies of the values of those variables for my $x ($one, $two, $three) { doesn't make copies, but rather aliases $x to the variables one at a time:

    my $one = 1; my $two = 2; my $three = 3; my @arr = ($one, $two, $three); $arr[0] += 10; print "\$one = $one\n"; # still 1 for my $x ($one, $two, $three) { $x += 0.5; } print "\$one = $one\n"; # changed to 1.5 for my $x (@arr) { $x += 0.1; } print "\$one = $one\n"; # still 1.5, no link between $arr[0] and $one

    So arrays contain values, but for loops through the "things" specified in the list you specify and if that "thing" is a variable, you can change it.

    There is an exception though. The @_ array used for parameters to subroutine calls:

    my $one = 1; my $two = 2; my $three = 3; sub direct { $_[0] += 10; $_[1] += 9; } sub indirect { my ($a,$b,$c) = @_; $a += 99; $b += 99; } print "\$one = $one\n"; # 1 direct($one, $two, $three); print "\$one = $one\n"; # changed to 11. $_[0] was an alias to $one. indirect($one, $two, $three); print "\$one = $one\n"; # still 11. The $a was assigned a copy of the +value. It's not an alias

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

Re: Array of variables
by sundialsvc4 (Abbot) on May 28, 2013 at 20:35 UTC

    Indeed, if there is but one fragment of Perl-voodoo that you need to read about right away, it would be:   references.   (See: perldoc perlref, perldoc perlreftut, and their many brethren.)

    The essential idea is a disarmingly simple one:   a “reference” is “a single, scalar thing” (so it qualifies to be the value of a variable, or an element in an array or in a hash ...) which can “refer to” anything-at-all.   Perl takes care of all the messy memory-allocation, reference-counting and garbage-collection headaches for you, and for the most part, it is also quite prescient when it comes to understanding the code that you’ve written.   (Perl was written by people who need to get work done, not by computer academics.)

    You can pretty much build “arrays of hashes of hashes of arrays of ...” with impunity, because you actually build “arrays of references to hashes of references to hashes of references to arrays of ...”   (This is also where the Perl slang terms, “arrayref” (== reference to array) and “hashref” (== reference to hash) come from.)

    The Perl language also allows you several different ways to write the same thing ... the choice being up to you.   Unlike most other languages, Perl does not impose “the designer’s one-and-only opinion as to what is ‘the right way to do it’ ” upon you.   This philosophy gives rise to TMTOWTDI == “Tim Toady” == There’s More Than One Way To Do It.™”

      I'm sorry, but I downvoted this because I think its really unhelpful. Parts of it are wrong and other parts are misleading—but I'm also getting a headache trying to read it.

      Could you please elide the random typography? I feel like you're trying to communicate something but it's getting lost along the way.

        Are you seriously criticizing him for using proper typography? We’re living in the 21st century, for Larry’s sake. Unicode is everywhere; we no longer have to use typewriter quotes or ASCII equivalences (e.g. ... instead of …).

        Could you please elaborate on what parts of the post you think are wrong or misleading?