(This is HTMLized version for http://svn.openfoundry.org/pugs/docs/Perl6/FAQ/Capture.pod - before Perl6::Doc's release on CPAN, please refer to that URL for the latest version.)
DESCRIPTION
This FAQ answers questions about Capture objects,
as well as their uses in bindings and function calls.
What happened to references?
They have been superseded by Capture objects.
What is a Capture?
A Capture is an object representing arguments in a function call.
For example,
the arguments in say("Hello",
"World")
is a Capture object denoted by \("Hello",
"World")
.
Can I see what captures look like?
Does \$x no longer work?
Prefix \
is now the Capture constructor.
These are all equivalent:
my $xcap1 = \$x;
my $xcap2 = \($x);
my $xcap3 = \($x :);
All three represent an argument list with a single invocant $x
, and hence are all equivalent with each other:
$xcap1 === $xcap2 === $xcap3; # true
What about capturing multiple arguments?
Here's how Captures look like deferred argument lists:
sub make_car (
Str $model,
Str $color? = "black",
Int $doors = 4
) { ... }
# some positional, some named
my $car_cap = \("Model T", doors => 2);
# passing the opaque Capture as actual function arguments
my $car = make_car(*$car_cap);
# extracting a specific positional argument
say "The thing is $car_cap[0]"; # Model T
# or by name
say "It has $car_cap<doors> doors" # 2 doors
How do I extract all positional arguments or all named arguments?
As you can see above, a Capture object holds both positional and named parts. If you want to retrieve all positional parts, there are two ways:
$cap[]; # postfix .[]
@$cap; # prefix @
Both forms flatten under list context, so they may be used interchangeably. However, only the postfix .[]
form interpolates in a string.
Similarly, access to named arguments is available by treating the Capture as a hash:
$cap{}; # postfix .{}
%$cap; # prefix %
Note that the positional parts do not include the invocant.
What do you mean by "invocant"?
When you call an object's method, the self
inside the method is set to that object. These are all equivalent:
$fh.say("Hi!");
say $fh: "Hi!";
say($fh: "Hi!");
Note that an argument list can have at most one invocant. You can construct a Capture object with an invocant using the same syntax:
my $cap = \($fh: "Hi!");
To get back the invocant from a Capture object, use the prefix "$" operator:
my $fh = $$cap;
So this Perl5ish equivalence still holds:
$x === $(\$x);
What about multi-dispatch?
Multi-dispatch governs cases where multiple subroutines or methods share the same name, relying on the arity and types of tie-breaking parameters in their parameter list (Signature):
multi f ($x: $z) { say 'A' }
multi f (Int $x, Int $y: $z) { say 'B' }
multi f (Str $x, Str $y: $z) { say 'C' }
f(1, 2); # goes to A
f(1, 2, 3); # goes to B
f('x', 'y', 'z'); # goes to C
During multi-dispatch, a tie-breaking parameter may bind to the invocant argument (e.g. for multi-methods), or one of the positional arguments.
However, regardless of single- or multi- dispatch, the argument list (Capture) can never have more than one invocant. Typically, the presence of an invocant indicates a method-call (which may fall back to a subroutine-call); the lack of invocant means a subroutine-call.
1.foo(2); # Int.foo with 1 as "self"; if not
# found, fallback to foo(1, 2)
foo(1: 2); # same as above
bar(1, 2); # never looks at Int.bar; calls &bar
# in lexical/package scope
Method/subroutine calls are determined by the presence of an invocant at the calling site. Single/multi dispatch are determined by the presence of "multi" in the declaration site. The two concepts are entirely orthogonal.
What happens when a named argument is repeated?
Let's look at some examples:
sub make_car (Int $doors) {
say "My car has $doors doors";
}
make_car(
doors => 2, doors => 4
); # 4 doors
sub board_ark (@animal) {
say "@animal.elems() animals boarded the ark";
}
board_ark(
animal => "moose", animal => "elephant"
); # 2 animals
A Capture object may hold named arguments that occur twice or more. When it's bound to a variable in the Signature, if the sigil is @
, then it expands to a list of all arguments (in the order they were specified).
Otherwise (i.e. if it's bound to a scalar or a slurpy hash), the last argument overrides the previous ones.
What do *$x, *@x and *%x mean?
The prefix *
method casts an object into a Capture object, and merges it into the Capture currently being constructed (e.g. an argument list):
my $cap = \(1, 2, x=>42);
f(*$cap); # f(1, 2, x=>42)
Array, List, Hash and Pair objects cast into Capture objects in obvious ways:
my $a = [1, 2]; f(*$a); # f(1, 2)
my $l = (1, 2); f(*$l); # f(1, 2)
my $h = {x => 42}; f(*$h); # f(x => 42)
my $p = (x => 42); f(*$p); # f(x => 42)
It also works with the @
and %
sigils:
my @a = (1, 2); f(*@a); # f(1, 2)
my @a := [1, 2]; f(*@a); # f(1, 2)
my %h = (x => 42); f(*%a); # f(x => 42)
my %h := {x => 42}; f(*%h); # f(x => 42)
What does $x = \@y mean?
The same as $x = (@y: )
. That is, a Capture of one array as invocant.
Unlike in Perl 5, this means that you can get back the Array object with:
my @y2 := $$x; # get back the invocant
instead of:
my @y2 := @$x; # WRONG: $x contains no positional parts
Manipulating the original value via the $x capture is still possible:
$$x.push("another element");
Note the need for the extra $ sigil, implying we are accessing the captured invocant. @$x.push()
would mean an attempt to add an extra positional argument into $x
; this would fail as all parts are immutable in an Capture object.
(Captures are immutable; their underlying data may not be.)
So $x = @y does not mean $x = \@y anymore. Then, what does it mean?
It means assigning $x
with the object bound to @y
(typically an Array object).
This does not create Capture objects; to get back @y
, @$x
would do.
Also note that all these forms mean the same thing:
@y;
@@y;
@@@y;
@y[];
@y[][];
@y[][][];
Does this mean I can't have something akin to a reference to a reference?
You can, as a Capture can contain another capture object in its invocant slot:
my $x = \\3;
say $$$x; # same as "say 3"
Can I create a "pass-through" function that captures all arguments?
Yes, using the \$
signature:
sub f (\$args) { g(*$args) }
f(1, 2, x => 42); # same as g(1, 2, x => 42)
The $args
above becomes a Capture object.
What about delegating a method?
Perl 6 has a few other provisions for this (e.g., .wrap), but if you want more control over invocation, you can take advantage of the default Signature for methods, which puts all positionals in @_
and named arguments in %_
:
method front_meth {
$!real_obj.back_meth( *@_, *%_ );
}
You can also take the argument list as a Capture object, and merge it with another method invocation:
method front_meth (\$args) {
$!real_obj_A.back_meth( *$args );
}
This works because when there is already an invocant present, further invocants in the constructing argument list will be ignored.
How is @x = (1, 2, 3) different from @y := (1, 2, 3) ?
The latter is an error. :-)
The :=
operator binds its left hand side (a Signature object) to its right hand side (a Capture object), so the latter form is akin to:
sub foo (@y is rw) { ... }
foo(1, 2, 3); # FAIL: three arguments passed where one is expected
However, these forms are valid:
*@y := (1,2,3); # slurpy @
@y := ((1,2,3):); # list as invocant
@y := ((1,2,3),); # list as first positional
@y := (y => (1,2,3)); # named binding
But they are still different from the assignment form.
How is @x = (1, 2, 3) different from *@y := (1, 2, 3), then?
This means that while @y
holds the values 1, 2, and 3, you cannot modify the container itself, so this won't work:
@y.push(4); # FAIL: cannot find method: List.push
On the other hand, because variables are initialized by their sigils, so these two mean the same:
my @x := []; # new Array object
my @x; # implicitly does the same thing
so @x = (1, 2, 3)
would simply populate the previously allocated Array object with new elements.
Is there any difference between $x = (1, 2, 3) and @y = (1, 2, 3)?
Yes. The right-hand side in both case is a single List object constructed with the list-associative infix:<,>
operator, but it is flattened in the second case, and its elements are put into the previously allocated Array container bound to @y
:
$x.push(0); # FAIL: cannot find method: List.push
@y.push(0); # works just fine
Is there any difference between $x = [1, 2, 3] and @y = [1, 2, 3]?
Yes. As in Perl 5, the Array constructor circumfix:[ ]
does not flatten under list context, so @y
receives a List with one element (an Array object), which then becomes @y[0]
:
$x.elems; # 3
@y.elems; # 1
The cases below are similar to Perl 5 as well:
$x.push(0); # works - $x.elems becomes 4
@y[0].push(0); # works - @y.elems remains 1
@y.push(0); # works - @y.elems becomes 2
Is there any difference between $x := [1, 2, 3] and @y := [1, 2, 3]?
For the usual method-based operations, they are pretty much interchangeable:
$x.push(0); # works - $x.elems becomes 4
@y.push(0); # works - @y.elems becomes 4
However, they differ when you try to assign something into them:
$x = 42; # FAIL - Array doesn't handle scalar assignment
@y = 42; # works - @y.elems is now 1
Note that $x = 42
fails because the :=
in $x := [1, 2, 3]
changes the underlying container of $x from a Scalar into an Array. Compare this with the assignment case:
$x = [1,2,3];
$x = 42; # works just fine
and also binding into an integer:
$x := 41;
$x = 42; # FAIL - Int doesn't handle scalar assignment either
Recent Comments