in reply to Why does assignment change the result?

If you pass in more than two args or change the assignment from being what is essentially a no-op (such as passing in a tied value) youll see the two are quite different. One returns an array and the other a list. A list in scalar context is its rightmost element, an array in scalar context is its size. Additionally @_ is special, assigning to it alters the original variables passed in. Im actualy surprised you dont get an attempt to modify a read only value error from two_hard().

---
$world=~s/war/peace/g

  • Comment on Re: Why does assignment change the result?

Replies are listed 'Best First'.
Re^2: Why does assignment change the result?
by jdporter (Paladin) on May 23, 2007 at 18:31 UTC
    Additionally @_ is special, assigning to it alters the original variables passed in.

    No, it doesn't. Assignment to elements of @_ will change those variables; assignment to @_ replaces its contents entirely. Isn't Perl wonderful? :-)

    Update: IOW, what suaveant said.

Re^2: Why does assignment change the result?
by suaveant (Parson) on May 23, 2007 at 18:24 UTC
    I am not positive but I think by assigning to @_ wholesale he is replacing the aliases, not writing to them.

                    - Ant
                    - Some of my best work - (1 2 3)

      whoops. good catch. still anything that assigns to @_ is a code smell to me.

      ---
      $world=~s/war/peace/g

        <sarc>But then you can use shift and pop without passing any arguments... think of all the typing you will save!</sarc>

        :)

                        - Ant
                        - Some of my best work - (1 2 3)

Re^2: Why does assignment change the result?
by blazar (Canon) on May 23, 2007 at 21:58 UTC
    A list in scalar context is its rightmost element, an array in scalar context is its size.

    You're right of course. But then you got me thinking... why does the ()= trick work? It is supposed to put its rhs in list context and then is generally put back in scalar context to get the length of a generated list... Is it special cased?

    print scalar(()=eval { wantarray ? qw/foo bar baz/ : 1 });

    (This prints 3 of course.)

      I'm fairly sure it's not special cased. It's essentially what you said. (Look at the associativity see how the context propagates and look at the precedence to see who wins :).

        Yes, but then in the example above, why isn't the rightmost element of the list returned instead of its length? There's no array involved.

      I'm baffled by this too. How can it print 3 when there never is an array? Or is there? (I only see an empty list assigned to, which is not an array, right?)

        The "lists always return the last item and only arrays return the length" is a popular but very misleading meme.

        An array in scalar context returns the number of elements. An array slice in a scalar context returns the last value of the list that would be returned in a list context. A "literal list" (a list of expressions enclosed in parens and separated by commas) in a scalar context evaluates the last expression in a scalar context and returns the resulting value. Note that this may not be the same as the last value that would be returned if this "list" were evaluated in a list context. A list assignment in a scalar context returns the number of values on the right-hand side of the list assignment.

        The term "list" with regard to Perl is not a precise term meaning only one thing. There are lots of kinds of lists in Perl (and an array is a kind of list, especially if you define an array slice as a "list"). Each different type of "list" in Perl returns a different thing in a scalar context, usually something rather appropriate1.

        There are lots of discussions of this around the Monastery so I'm bit surprised that so many participants of this thread remember so little from them. :)

        - tye        

        1 Note that what an array slice returns (or was it hash slices or both?) in a scalar context was never designed nor documented and was only implemented after a patch I wrote and forgot about years ago. It also happens to be one of the rare cases when Perl "makes a list (of scalar values on the stack) despite a scalar context and then throws all but one of them away", which Perl usually avoids.

        Update: Had I better understood Perl's list/scalar contexts at the time I wrote the patch, I probably would have at least wanted to make the patch instead pass the scalar context inward to the array slice indices expression (or to the hash slice keys expression) so that only one index (key) was calculated and then used to determine which single element to return.

Re^2: Why does assignment change the result?
by Anonymous Monk on May 23, 2007 at 18:36 UTC

    If I pass in three arguments, I get the same output.

    print "two easy: " . two_easy( 'one', 'two', 'three' ) . "\n"; print "two hard: " . two_hard( 'one', 'two', 'three' ) . "\n";

    I don't understand what you mean about passing in a tied value.

      To paraphrase what demerphq said :

      • Your "two_hard" sub returns an array (@_).
      • Your "print" statement uses the concat "." operator, which makes the usage of the return value in a scalar context
      • In a scalar context, an array evaluates to the number of elements (2)
      Similarly, your "two_easy" sub returns a LIST. (Because you picked out elements of the array, using an array slice).

      In a scalar context, a list evaluates to the last element.

      For now, you can ignore the "tied" comment.

      Update: jdporter is apparently a faster typist than I am. His post essentially says the same thing.

           "An undefined problem has an infinite number of solutions." - Robert A. Humphrey         "If you're not part of the solution, you're part of the precipitate." - Henry J. Tillman