in reply to Accessing Arguments inside Subroutines via @_
Hello citi2015, and welcome to the Monastery!
The final sentence of the paragraph in perlsub you quote is this:
Assigning to the whole array @_ removes that aliasing, and does not update any arguments.
This was new to me. It answers your question, but I would be interested to know what motivated the design decision behind it.
Hope that helps,
Re^2: Accessing Arguments inside Subroutines via @_
by LanX (Saint) on Mar 20, 2015 at 03:07 UTC
|
> I would be interested to know what motivated the design decision behind it.
I think it follows the normal inner mechanism.
The elements are aliases not the array holding them.
Think about how shift @_ deletes an alias.
One might argue that the array should not be writable, but its sometimes necessary to rewrite @_ before doing a goto &sub .
| [reply] [d/l] [select] |
Re^2: Accessing Arguments inside Subroutines via @_
by LanX (Saint) on Mar 21, 2015 at 12:43 UTC
|
I think what is really troubling you is the ambiguity between setting a symbol's slot and assigning to a symbol in Perl. (not sure if this is proper terminology)
Pure Perl has neither an explicit alias operator, nor an explicit unalias operator.²
So if a scalar variable $a is an alias to $b you can't easily say $a=42 without changing $b , i.e. replacing the alias in the $a -"slot" with a literal 42.¹
But when operating with arrays like @_ you have the choice.
$_[0]=42 is accessing the alias behind, but @_=(42) will replace the content of the slot.
DB<106> sub repl { @_=(42); print "> $_[0]"; }
DB<107> $a=666
=> 666
DB<108> repl $a
> 42
DB<109> $a
=> 666
It has already been shown how to access multiple aliases at once (slicing), similarly you can use splice to access multiple slots of an array at once.
I hope the distinction between setting a slot and assigning to an alias is clearer now. :)
¹) But you can always use my $a=42 in a new scope or local $a=42 if it's a package var.
²) like tie and untie | [reply] [d/l] [select] |
|
Hello LanX,
I think what is really troubling you is the ambiguity between setting a symbol's slot and assigning to a symbol in Perl.
I’m not sure if I understand the distinction you’re making here, but my current understanding of a Perl alias is that it’s in some ways analogous to a smart pointer. That is, it has its own identity as a scalar value (of type “alias”), but under certain conditions it behaves “transparently” as the entity it aliases, like a dereferenced pointer. To explain what I mean: I was experimenting with various permutations of the following code:
and the output shows that following unshift @_ the element $_[1] is now an alias for the first argument. So, when explaining how @_ functions in a subroutine, I would no longer say “$_[0] is an alias for the first argument,” but rather “$_[0] is initialised to a (scalar value which is an) alias for the first argument.”
And the difference in behaviour between, e.g., @_ = reverse @_ and ( $_[0], $_[1] ) = ( $_[1], $_[0] ), comes down to whether the aliases act “transparently” or ”opaquely.” When elements of @_ are accessed individually — whether singly or as part of an array slice — they behave “transparently,” but when the array @_ is assigned-to — via = or splice — its alias values are accessed “opaquely,” meaning their referents remain unaffected.
Well, that’s my current understanding, and it may be just a convoluted way of repeating your explanation in different words. Anyway, I think I now understand what’s going on a little better than I did before. :-)
Update: Fixed typo.
Thanks for the help,
| [reply] [d/l] [select] |
|
Well you asked for the "why" not for the "how" ... :)
I took a look into the Panther book and experimented with Devel::Peek and the implementation of aliases seems simpler than a magic data structure of type alias.
Arrays (AVs) are composed from C-structures with pointers to C-structure(s) realizing scalars (SVs).
So $_[0]=666 updates the underlying scalar ( what I called "assigning" ) while @_=(666) creates the pointer to a new scalar ( "setting" ).
In the following dump the scalar value for $x is held within SV = IV(0x88f2498) at 0x88f249c
The array's first slot will point to that same structure before and after updating with $_[0]=666 (#markers added)
But creating new entries with @_=(666) will replace the pointer in this AV-slot to a new SV.
I hope the "how" is clearer now! :)
| [reply] [d/l] [select] |
|
#!/usr/bin/perl
no strict;
use warnings;
use feature qw/say/;
$a = 42;
*b = *a;
say $b; # 42
$b = 69;
say $a; # 69
I can't think of a way of doing this with lexicals off the top of my head, though.
nor an explicit unalias operator.²
So if a scalar variable $a is an alias to $b you can't easily say $a=42 without changing $b , i.e. replacing the alias in the $a -"slot" with a literal 42.¹
I don't think this is needed. Suppose that you have variables - let's say lexicals - $a and $b, with the latter being aliased to the former. Unalias $a would mean creating a new lexical that's not related to $b anymore, so why not just declare a new lexical with the same value (my $c = $b) and use that instead? The result's the same, and it's arguably clearer, since if you look at any line in isolation there's no confusion over whether $a is (still) aliased to $b anymore.
OTOH there's something to be said in favor of explicit alias and unalias operators as well. I'd not be surprised at all if there were CPAN modules that implemented this.
| [reply] [d/l] |
|
I just wanted to highlight why it makes sense that assigning to @_ doesn't write thru to the aliases.
my and local were already mentioned in my footnote, when using typeglobs I'd strongly suggest to prefer *b = \$a; over *b = *a;
But these mechanisms are no big help if you want named parameters in subs cause those are lexicals, (which should be the preferred variable flavor).
> I'd not be surprised at all if there were CPAN modules that implemented this.
see Data::Alias or Lexical::Alias and their discussion in PBP
Perl6 aims to handle aliasing consistently.
| [reply] [d/l] [select] |
Re^2: Accessing Arguments inside Subroutines via @_
by citi2015 (Initiate) on Mar 20, 2015 at 03:07 UTC
|
Thanks a lot, Athanasius.
No design decision behind it. A newer read that code from one book and find this error, I just realise I cannot explain. so I do my test and post the question on the community.
Thanks again for the help.
| [reply] |
|
Hello citi2015,
I meant Perl’s design decision to remove the aliasing when @_ is assigned-to within a subroutine.
You can, of course, do the swap by explicitly accessing the subroutine arguments as individual elements of @_:
sub swap
{
my $temp = $_[0];
$_[0] = $_[1];
$_[1] = $temp;
}
— but note the necessity of “remembering” the initial value of $_[0] by storing it in a temporary variable. And I think that answers my question: if the aliasing were not removed, @_ = reverse @_ would produce wrong results, because some elements would be changed (assigned-to) before they were assigned-from.
Hope that helps,
| [reply] [d/l] [select] |
|
DB<100> sub rev { ($_[0],$_[1]) = ($_[1],$_[0]) }
DB<101> @a=("A","B")
=> ("A", "B")
DB<102> rev @a
DB<103> @a
=> ("B", "A")
| [reply] [d/l] |
|
|
|
|
sub swappy {
($_[0], $_[1]) = ($_[1], $_[0])
}
...roboticus
When your only tool is a hammer, all problems look like your thumb. | [reply] [d/l] |
|
|