[Perl 6 page]

[Table of Contents] [first in this series] [previous] [next]

Passing Collections as Parameters

This is part of a series which describes the Information Model of Perl 6. It is theoretical rather than an exact description of any real implementation.. The details in this installment are not quite spelled out in the Synopses, but completely consistant with them except where noted.

The previous installment shows how item variables (lvalues) and values are passed to formal parameters that are also declared as items. By item I mean the parameter and the callerís variable were both declared using the $ sigil. Now we will look at the case of using other kinds of collections and sigils.

The behavior of all the sigils other than $ are the same in this regard, so this essay will simply use @. The others behave analogously. Crossing different sigils (e.g. passing a %hash to a function declared to take an @array) is another story and will be covered elsewhere. [ add link later ]

General Directions

The $ sigil is different from the others in a couple of respects. First, a variable declared with $ may be bound to any kind of object, including other kinds of containers. So, you might have some $variable that is bound to another type of container (say, an Array), or bound directly to a value with no container at all.

Just to be clear, variables declared using the @ sigil can only be bound to objects that do the Positional role (likewise for the other sigils).

Meanwhile, the Item Container is transparent. Methods sent to a variable bound to an Item Container actually talk to the object it contains. In contrast, the other containers appear normally to you as objects.

Recall that containers are associated with lvalueness.

For the callerís argument, what the underlying lvalue is is all that matters, not how the variable is named. A variable named with an $ that is bound directly to an Array will behave exactly like the variable declared using @. So will any Array produced by an expression that is not directly a variable name.

The only difference between $x and @x when bound to the same Array object is with slurpy parameters. That is not covered here. [ add link later ]

Keeping these things in mind, and knowing what we do from the previous installment, the behavior of parameter-passing situations involving different sigils should hopefully be compelled from these principles. Or, the behavior should at least be fairly clear.

All the Possibilities

The functionís parameter may be declared with a @. Or, it may be declared using $ and still be passed an Array (or other Positional) object. Furthermore, it may have any of the 4 passing modes (readonly, rw, copy, ref).

The caller may pass an Array (or other Positional) object, or may pass an Item that contains one.

Array Item
@param is readonly binds argument w/proxy binds itemís contents w/proxy
@param is rw binds argument binds itemís contents
@param is copy copies Array copies contained Array
@param is ref binds argument binds itemís contents
$param is readonly binds argument w/proxy like before
$param is rw binds argument like before
$param is copy copies Array like before
$param is ref binds to whatever is given

Passing something thatís not on the chart could be considered case 0.

If you pass ďsomething elseĒ to a $param, thatís covered on the previous page. If the actual argument is not any kind of container, than itís a non-lvalue.

If you pass something thatís not an Array or an item containing an Array (or other object that does Positional) to a @param, then the call is simply rejected. Note in particular that no attempt is made to convert the argument into something that might fit. That is different from declaring Positional $param which would treat the Positional type like any other type (and thatís another series all together [ and an eventual link ]).

However, there is some conversion possible between different kinds of containers, under limited circumstances. This is covered later [ link ]).

Easiest: ref parameter

The concept behind the ref parameter is that it will bind to whatever you give it, without complaining or adapting. That is simple enough with $param. But @param cannot bind to an item, only to a Positional container.

Consider an example:

sub f4 (@array is ref)
 { ... }

my @A;
my $b = @A;

f4(@A);  # case 1
f4($b);  # case 2

parameter illustration In case 1, @array will be bound to the same Array object as @A. I feel compelled to say more about it because the illustration is so much taller than this paragraph, but thereís really nothing more to say about it. This is as simple as it gets.


parameter illustration But what should happen in case 2? Being ref, we expect it to take it without complaining. It canít bind to the Scalar that $b is. Since normally you will forget about the Item Container and think about the contained value as ďbeing inĒ that variable, the intent is clear: @array will bind to the object contained in $b.

This is illustrated in the diagram to the right. The irrelevant parts (not the parameter nor argument) are faded.

This is not aliasing $bís container, as with the scalar parameter. If $b changes via assignment to contain a different array, or something thatís not an array at all, @array will not notice.

rw parameter

If you declare $param is rw, and you pass it an Item, then thatís just the case from the previous page.

parameter illustration If you pass it some other kind of container such as an Array, then rather than rejecting the call, it consideres the collection object as a type of LValue. This situation will be called case 3. Notice that it is like case 1 above and left, but naming the parameter with the more generic sigil. After all, $ variables may bind to other kinds of containers, so it works just like the @parameter case when given the oppertunity.

If you declare @param is rw, it is no different from @param is ref, shown above. Unlike the scalar parameter, there is nothing that could bind to @param that is not an lvalue, as Array (or other Positional) is a container and hence qualifies.


readonly parameter

If you declare $param is readonly (or just $param since that is the default, and you pass it an Item that contains another collection, does the lvalueness and the readonlyness apply to the variable or the collection?

If you meant the latter, then you should have written @param instead of $param. Passing Items to $param is the same regardless of what the Item contains.

If you declare @param is readonly, you might pass it an Array or an Item containing an Array. The issues on what to do with the latter are the same as with the ref case. Thereís not a lot of choice in the matter. If you think that assigning to $b should make @param refer to something else on the fly, then you should have declared $param instead.

The difference is that you need to enforce the readonly nature while still aliasing the original. This means introducing a Read-Only Proxy. This serves the same purpose as the ones we saw for Items, but is of course based on the Positional role. The proxy will pass along FETCH requests, but block STORE requests and any mutating methods defined for Positional, such as shift. This is discussed at length on another page.

In addition, $param will accept an Array object just like @param, and treat it the same way. Both possibilities are shown on the first diagram (cases 4a and 4b).

The diagrams are similar to cases 1 and 2 above, but have the R-O Proxy inserted. The same notes apply as before with the Itemís proxy.

parameter illustration parameter illustration

copy parameter

If you declare $param is copy and pass it an Item, it works as before, binding to a copy of the Item pointing to the same contents. If you wanted to copy the Array instead, you should have declared it as @param.

If you pass an Array, it treats it the same as if you wrote @param. Both cases, 6a and 6b, are shown on the diagram.

The example uses Int objects which are value types, but the drawing should be clear that the copied Array points to the same objects as the original, which would be more meaningful if they were mutable objects.

If you declare @param is copy and pass it an Array (or other Positional) object, then itís clear that the proffered collection is what is to be copied. A new Array (the default container for Positional) is created and assigned the elements from the original.

parameter illustration

If you pass it an Item containing an Array, did you mean to copy the Item or the contained Array? Well, the parameter canít accept the Item, so like with the other modes, it assumes you meant the contained Array, treating it the same as if you had passed the Array directly. If you meant the other way, you should have declared it as $param.

parameter illustration

To continue

The next page discusses how things stored in collections can still provide lvalues.

Or, see the Table of Contents for other subjects.

Notes

By ďother type of containerĒ, I mean precicely those things which are allowed to bind to variables declared with other sigils. Specifically, any object that does at least one of the roles associated with a standard container type.

Orthodoxy

Checked for technical accuracy in May 2009. Initial presentation, awaiting review feedback.

The following interpretations were made of the statements in the Synopses, as illustrated on the previous pages: