Re: [Boston.pm] something about @_ is different?
"Greg London" <email-2Ro/Dj86MvDSUeElwK9/[email protected]> Wed, 22 May 2019 18:09:32 -0400
| Newsgroups | gmane.comp.lang.perl.perl-mongers.boston |
|---|---|
| Message-ID | <[email protected]> |
On Tue, May 21, 2019 7:18 pm, Ben Tilly wrote:
> That said, it is actually consistent.
my $alpha="aaa";
my $bravo="bbb";
my @arr_o_refs = ( \$alpha, \$bravo );
@arr_o_refs = reverse(@arr_o_refs);
print Dumper \@arr_o_refs;
[
\"bbb",
\"aaa"
]
If someone knew the rules to how normal arrays worked in perl,
they need to learn 3 different exceptions to understand @_ such as:
1: @_ is like an array of references back to the original caller variables.
2: but when you get/set an element in @_, perl automatically dereferences
the reference for you.
3: assigning to the entire @_ array doesnt act like assigning to a
normal array of references. Rather its like calling local() on the
@_ array, but then it also ignores lexical scope normally associated
with local()
"It all follows logically."
Its logically consistent to :
1: the rules of arrays
PLUS
2: several exceptions to the rules of arrays that only applies to @_
To that set of rules, with the exceptions, it is logical.
On Tue, May 21, 2019 7:18 pm, Ben Tilly wrote:
> If you want to assign to all the individual elements in the passed in
> array, you can. Try this:
>
> sub swapper { @_[0..$#_] = reverse @_;
> }
>
>
> That said, it is actually consistent. It just doesn't match the mental
> model that you had.
>
> Perl is pass by reference, assign by value. All else follows.
>
>
> @_ starts off as an array of aliased elements. But assign to @_, and
> you've created a new array with new values. Assign to the slots of @_,
> and you've replaced the old values with new values in the original
> variables. (That's the "pass by reference" bit.) If you assign one value
> to another, you copy the value. If you then modify the second copy in
> place, the original does not change.
>
> The assignment by value is a shallow copy. That means that when you copy
> a reference, both copies point to the same underlying data. Compare the
> following:
>
>
> my $foo = "Hello"; my $bar = $foo; # Copies data $bar .= ", World";
> say($foo); # Prints "Hello\n"
>
> my $foo = \"Hello"; my $bar = $foo; # Copies reference to same data $$bar
> .= ", World";
> say($$foo); # Prints "Hello, World\n"
>
> It all follows logically. And, modulo various optimizations, this is
> exactly how it works under the hood.
>
> On Tue, May 21, 2019 at 3:50 PM Greg London <email-2Ro/Dj86MvDSUeElwK9/[email protected]> wrote:
>
>
>> Ugh. I dont like this.
>>
>>
>> Its linguistically inconsistent.
>> Assign to an element in array assigns back to caller var.
>> Assign to whole array disconnects the aliases
>> that ties @_ back to the caller vars and assigns to a local version of
>> @_?
>>
>>
>> If someone wants to disconnect the underlying aliases,
>> call local() and put the syntactic sugar there.
>>
>> And then assigning to @_ without local() would work just
>> like assigning to all the individual elements in array.
>>
>> Perl can be disappointing sometimes.
>>
>>
>> Greg
>>
>>
>>
>>
>> On Tue, May 21, 2019 2:12 pm, Conor Walsh wrote:
>>
>>> Assigning to @_ is weird and I don't recommend it. It's full of magic
>>> aliases, which in some cases means you change the caller's
>>> variables, which is usually not what you want.
>>>
>>> Check the beginning of perldoc perlsub.
>>>
>>>
>>>
>>> On Tue, May 21, 2019, 2:04 PM Greg London <email-2Ro/Dj86MvDSUeElwK9/[email protected]>
>>> wrote:
>>>
>>>
>>>
>>>>
>>>> Hm, it could be a caffeine defficiency, but it seems that @_ is
>>>> being treated different than other arrays.
>>>>
>>>> I can create a normal array:
>>>> my @normal_array=('a','b');
>>>>
>>>> and I can assign an entirely new list to it:
>>>> @normal_array=reverse(@normal_array); # assign to array
>>>>
>>>>
>>>>
>>>> and I can assign to it in parenthesis an entirely new list
>>>> (@normal_array)=reverse(@normal_array); # assign to (array)
>>>>
>>>>
>>>>
>>>>
>>>> And those assignements take hold as I would expect.
>>>>
>>>>
>>>>
>>>> When I use the exact same syntax for the @_ array instead
>>>> of @normal_array, it doesn't work as expected: sub swapper{ (@_) =
>>>> reverse(@_); # this doesn't seem to do anything. }
>>>>
>>>>
>>>> my @other=('x','y'); swapper(@other); print Dumper \@other;
>>>>
>>>> Pretty sure this code used to work,
>>>> but that was many moons ago.
>>>>
>>>> Thoughts?
>>>>
>>>>
>>>>
>>>> Greg
>>>>
>>>>
>>>>
>>>> Here's the script in one big copy/paste block:
>>>>
>>>>
>>>>
>>>>
>>>> my @normal_array=('a','b'); print "normal_array is "; print Dumper
>>>> \@normal_array;
>>>> @normal_array=reverse(@normal_array); # assign to array
>>>> print "normal_array is "; print Dumper \@normal_array;
>>>> (@normal_array)=reverse(@normal_array); # assign to (array)
>>>> print "normal_array is "; print Dumper \@normal_array;
>>>>
>>>>
>>>> sub swapper{ (@_) = reverse(@_); }
>>>>
>>>>
>>>>
>>>> my $one = "i am one"; my $two = "i am two";
>>>>
>>>> swapper($one,$two);
>>>>
>>>> warn "one is '$one'"; warn "two is '$two'";
>>>>
>>>> _______________________________________________
>>>> Boston-pm mailing list
>>>> [email protected]
>>>> https://mail.pm.org/mailman/listinfo/boston-pm
>>>>
>>>>
>>>>
>>>
>>
>>
>> --
>>
>>
>> _______________________________________________
>> Boston-pm mailing list
>> [email protected]
>> https://mail.pm.org/mailman/listinfo/boston-pm
>>
>>
>
--