in reply to Re^2: Confused as to why the "casting context" is mis-behaving ("list vs array", again)
in thread Confused as to why the "casting context" is mis-behaving

This is not 100% correct. The array is returned from the function. But to get a hold of it, you should COPY it somewhere.

No, the array is copied before the function returns. You can observe that:

my @a= ( 'a' .. 'e' ); sub returnArray { return @a; } my @b= ( 'v' .. 'z' ); for( returnArray() ) { $_ .= '?' } for( @b ) { $_ .= '!' } print "@a\n"; print "@b\n"; __END__ a b c d e v! w! x! y! z!

And it is also not true that the function returns and then (after that) the scalar context decides to get the size of the array while the list context decides to copy the elements of the array.

The context gets passed in to the function, to the returning statement so that it can, when possible, avoid the work of creating a whole list of values just to throw that list away.

The method of returning information from a Perl function is to push zero or more scalar values onto the stack. return @array;, if called in a list context, loops over the array and pushes onto the stack, a copy of each element of the array. If you assign the return value to an array, then that assignment operator loops over the items on the stack and puts them into the array (whether each value is copied again here or the array just gets aliases to each of the original copies is an implementation detail and a matter of optimization that I have never needed to worry about).

- tye        

Replies are listed 'Best First'.
Re^4: Confused as to why the "casting context" is mis-behaving (return array)
by andal (Hermit) on Oct 25, 2010 at 08:39 UTC
    No, the array is copied before the function returns. You can observe that:

    You missed the point. It does not make any difference when the array is copied, before or after the return. The point was, when the function returns, the caller "can know" that some array was returned. So it makes difference what you return from the function, array or list or scalar.

    If you just wanted to say, that the array seen by the caller is not the same object as the array that was given to "return", then you are absolutely correct. But this is true for any returned object. Even references to arrays are copied, they are not the same references as the returned variables. Of course they reference the same array, but they are not the same references. So arrays are not an exception to this rule. It is general feature of the language.

    By the way, your code examples don't prove that the copying happens before the return. They just prove, that the "for" loop works with copies of values. Nothing else. When those copies were made stays unclear :)

      The point was, when the function returns, the caller "can know" that some array was returned.

      You'll have to explain how, then. The caller can't know that an array was involved because the caller only gets a list of scalar values pushed onto the stack.

      By the way, your code examples don't prove that the copying happens before the return. They just prove, that the "for" loop works with copies of values. Nothing else.

      Half of the code proves that the 'for' loop gets copies. The other half of the code proves that 'for' loops don't get copies when using an array. That's one of the major features of 'for' loops: They work on aliases not copies when possible. When calling a function, working on aliases isn't possible (because what gets pushed onto the stack is copies of each scalar value).

      - tye        

        You'll have to explain how, then. The caller can't know that an array was involved because the caller only gets a list of scalar values pushed onto the stack.

        I gave you examples of difference between returning array and list. For example, "return @ab" is not the same as "return (@ab, 'txt')". In the first case assignment of returned value to scalar will produce the count of elements in the array. In the second case it will produce the 'txt'. You can try "return ('txt', @ab)" and again you'll get count of elements in @ab when assigning to scalar. So the caller gets not the list of scalar values, but the list of objects, some of which may be hashes or arrays and some scalars.

        The copying magic happens when transferring objects from stack into the destination. The destination gets the copy of what was on the stack, but the copy might be flattened. So, if the list of scalars is needed, then the arrays and hashes will be expanded. But if the single scalar is needed, then the last object from the stack will be taken and "converted" into scalar.

        Half of the code proves that the 'for' loop gets copies. The other half of the code proves that 'for' loops don't get copies when using an array. That's one of the major features of 'for' loops: They work on aliases not copies when possible. When calling a function, working on aliases isn't possible (because what gets pushed onto the stack is copies of each scalar value).

        This is only because the values from the stack are copied into the list and only after that "for" has a chance to alias them. If you use the array directly, then the values are not copied (there's no stack involved). So the "for" loop has chance to alias the elements of the array directly. Remember the rule. Returned on the stack values are always copied before they can be used!