[ACCEPTED]-Are Perl subroutines call-by-reference or call-by-value?-perl

Accepted answer
Score: 42

Perl always passes by reference. It's just 34 that sometimes the caller passes temporary 33 scalars.

The first thing you have to realise 32 is that the arguments of subs can be one 31 and only one thing: a list of scalars.* One 30 cannot pass arrays or hashes to them. Arrays 29 and hashes are evaluated, returning a list 28 of their content. That means that

f(@a)

is the 27 same** as

f($a[0], $a[1], $a[2])

Perl passes by reference. Specifically, Perl 26 aliases each of the arguments to the elements 25 of @_. Modifying the elements @_ will change 24 the scalars returned by $a[0], etc. and thus 23 will modify the elements of @a.

The second 22 thing of importance is that the key of an 21 array or hash element determines where the 20 element is stored in the structure. Otherwise, $a[4] and 19 $h{k} would require looking at each element of 18 the array or hash to find the desired value. This 17 means that the keys aren't modifiable. Moving 16 a value requires creating a new element 15 with the new key and deleting the element 14 at the old key.

As such, whenever you get 13 the keys of an array or hash, you get a 12 copy of the keys. Fresh scalars, so to speak.

Back 11 to the question,

f(%h)

is the same** as

f(
   my $k1 = "a", $h{a},
   my $k2 = "b", $h{b}, 
   my $k2 = "c", $h{c}, 
)

@_ is still 10 aliased to the values returned by %h, but 9 some of those are just temporary scalars 8 used to hold a key. Changing those will 7 have no lasting effect.

* — Some 6 built-ins (e.g. grep) are more like flow control 5 statements (e.g. while). They have their own 4 parsing rules, and thus aren't limited to 3 the conventional model of a sub.

** — Prototypes 2 can affect how the argument list is evaluated, but 1 it will still result in a list of scalars.

Score: 12

Perl's subroutines accept parameters as 65 flat lists of scalars. An array passed 64 as a parameter is for all practical purposes 63 a flat list too. Even a hash is treated 62 as a flat list of one key followed by one 61 value, followed by one key, etc.

A flat list 60 is not passed as a reference unless you 59 do so explicitly. The fact that modifying 58 $_[0] modifies $a[0] is because the elements of @_ become 57 aliases for the elements passed as parameters. Modifying 56 $_[0] is the same as modifying $a[0] in your example. But 55 while this is approximately similar to the 54 common notion of "pass by reference" as 53 it applies to any programming language, this 52 isn't specifically passing a Perl reference; Perl's 51 references are different (and indeed "reference" is 50 an overloaded term). An alias (in Perl) is 49 a synonym for something, where as a reference 48 is similar to a pointer to something.

As 47 perlsyn states, if you assign to @_ as a whole, you 46 break its alias status. Also note, if you 45 try to modify $_[0], and $_[0] happens to be a literal 44 instead of a variable, you'll get an error. On 43 the other hand, modifying $_[0] does modify the 42 caller's value if it is modifiable. So in 41 example one, changing $_[0] and $_[1] propagates back 40 to @a because each element of @_ is an alias 39 for each element in @a.

Your second example 38 is a little tricky. Hash keys are immutable. Perl 37 doesn't provide a way to modify a hash key, aside 36 from deleting it. That means that $_[0] is not 35 modifiable. When you attempt to modify 34 $_[0] Perl cannot comply with that request. It 33 probably ought to throw a warning, but doesn't. You 32 see, the flat list passed to it consists 31 of unmodifiable-key followed by modifiable-value, etc. This 30 is mostly a non-issue. I cannot think of 29 any reason to modify individual elements 28 of a hash in the way you're demonstrating; since 27 hashes have no particular order you wouldn't 26 have simple control over which elements 25 in @_ propagate back to which values in %a.

As 24 you pointed out, the proper protocol is 23 to pass \@a or \%a, so that they can be referred 22 to as $_[0]->{element} or $_[0]->[0]. Even though the notation is 21 a little more complicated, it becomes second 20 nature after awhile, and is much clearer 19 (in my opinion) as to what is going on.

Be 18 sure to have a look at the perlsub documentation. In particular:

Any 17 arguments passed in show up in the array 16 @_. Therefore, if you called a function with 15 two arguments, those would be stored in 14 $_[0] and $_[1]. The array @_ is a local array, but 13 its elements are aliases for the actual 12 scalar parameters. In particular, if an 11 element $_[0] is updated, the corresponding argument 10 is updated (or an error occurs if it is 9 not updatable). If an argument is an array 8 or hash element which did not exist when 7 the function was called, that element is 6 created only when (and if) it is modified 5 or a reference to it is taken. (Some earlier 4 versions of Perl created the element whether 3 or not the element was assigned to.) Assigning 2 to the whole array @_ removes that aliasing, and 1 does not update any arguments.

Score: 5

(Note that use warnings is even more important than 21 use strict.)

@_ itself isn't a reference to anything, it 20 is an array (really, just a view of the 19 stack, though if you do something like take 18 a reference to it, it morphs into a real 17 array) whose elements each are an alias to a passed 16 parameter. And those passed parameters 15 are the individual scalars passed; there 14 is no concept of passing an array or hash 13 (though you can pass a reference to one).

So 12 shifts, splices, additional elements added, etc. to 11 @_ don't affect anything passed, though they 10 may change the index of or remove from the 9 array one of the original aliases.

So where 8 you call change(@a), this puts two aliases on the 7 stack, one to $a[0] and one to $a[1]. change(%a) is more complicated; %a flattens 6 out into an alternating list of keys and 5 values, where the values are the actual 4 hash values and modifying them modifies 3 what's stored in the hash, but where the 2 keys are merely copies, no longer associated 1 with the hash.

Score: 2

Perl does not pass the array or hash itself 18 by reference, it unfurls the entries (the 17 array elements, or the hash keys and values) into 16 a list and passes this list to the function. @_ then 15 allows you to access the scalars as references.

This 14 is roughly the same as writing:

@a = (1, 2, 3);

$b = \$a[2];

${$b} = 4;

@a now [1, 2, 4];

You'll note 13 that in the first case you were not able 12 to add an extra item to @a, all that happened 11 was that you modified the members of @a 10 that already existed. In the second case, the 9 hash keys don't really exist in the hash 8 as scalars, so these need to be created 7 as copies in temporary scalars when the 6 expanded list of the hash is created to 5 be passed into the function. Modifying 4 this temporary scalar will not modify the 3 hash key, as it is not the hash key.

If you 2 want to modify an array or hash in a function, you 1 will need to pass a reference to the container:

change(\%foo);

sub change {
   $_[0]->{a} = 1;
}
Score: 0

Firstly, you are confusing the @ sigil as 6 indicating an array. This is actually a 5 list. When you call Change(@a) you are passing 4 the list to the function, not an array object.

The 3 case with the hash is slightly different. Perl 2 evaluates your call into a list and passes 1 the values as a list instead.

More Related questions