Synopsis 6
by Damian Conway, Allison Randal
|
Pages: 1, 2, 3, 4
Editor's note: this document is out of date and remains here for historic interest. See Synopsis 6 for the current design information.
Parameter Traits
The following traits can be applied to many types of parameters.
is constant
- Specifies that the parameter cannot be modified (e.g. assigned to, incremented). It is the default for parameters.
is rw
- Specifies that the parameter can be modified (assigned to, incremented, etc). Requires that the corresponding argument is an lvalue or can be converted to one.
-
When applied to a variadic parameter, the
rwtrait applies to each element of the list: -
sub incr (*@vars is rw) { $_++ for @vars } is ref
-
Specifies that the parameter is passed by reference. Unlike
is rw, the corresponding argument must already be a suitable lvalue. No attempt at coercion or autovivification is made. is copy
- Specifies that the parameter receives a distinct, read-writeable copy of the original argument. This is commonly known as "pass-by-value."
-
sub reprint ($text, $count is copy) { print $text while $count-->0; } is context(TYPE)
- Specifies the context that a parameter applies to its argument. Typically used to cause a final list parameter to apply a series of scalar contexts:
-
# &format may have as many arguments as it likes, # each of which is evaluated in scalar context -
sub format(*@data is context(Scalar)) {...}
Advanced Subroutine Features
The &_ routine
&_ is always an alias for the current subroutine, much like the $_
alias for the current topic:
my $anonfactorial = sub (Int $n) {
return 1 if $n<2;
return $n * &_($n-1)
};
The caller Function
The caller function returns an object that describes a particular
"higher" dynamic scope, from which the current scope was called.
print "In ", caller.sub,
" called from ", caller.file,
" line ", caller.line,
"\n";
caller may be given arguments telling it what kind of higher scope to
look for, and how many such scopes to skip over when looking:
$caller = caller; # immediate caller
$caller = caller Method; # nearest caller that is method
$caller = caller Bare; # nearest caller that is bare block
$caller = caller Sub, skip=>2; # caller three levels up
$caller = caller Block, label=>'Foo'; # caller whose label is 'Foo'
The want Function
The want function returns an object that contains information about
the context in which the current block, closure, or subroutine was
called.
The returned context object is typically tested with a smart match (~~)
or a when:
given want {
when Scalar {...} # called in scalar context
when List {...} # called in list context
when Lvalue {...} # expected to return an lvalue
when 2 {...} # expected to return two values
...
}
or has the corresponding methods called on it:
if (want.Scalar) {...} # called in scalar context
elsif (want.List) {...} # called in list context
elsif (want.rw) {...} # expected to return an lvalue
elsif (want.count > 2) {...} # expected to return more than two values
The leave Function
A return statement causes the innermost surrounding subroutine, method,
rule, macro or multimethod to return.
To return from other types of code structures, the leave funtion is used:
leave; # return from innermost block of any kind
leave Method; # return from innermost calling method
leave &_ <== 1,2,3; # Return from current sub. Same as: return 1,2,3
leave &foo <== 1,2,3; # Return from innermost surrounding call to &foo
leave Loop, label=>'COUNT'; # Same as: last COUNT;
Temporization
The temp function temporarily replaces a variable, subroutine or
other object in a given scope:
{
temp $*foo = 'foo'; # Temporarily replace global $foo
temp &bar = sub {...}; # Temporarily replace sub &bar
...
} # Old values of $*foo and &bar reinstated at this point
temp invokes its argument's .TEMP method. The method is expected
to return a reference to a subroutine that can later restore the current
value of the object. At the end of the lexical scope in which the
temp was applied, the subroutine returned by the .TEMP method is
executed.
The default .TEMP method for variables simply creates
a closure that assigns the variable's pre-temp value
back to the variable.
New kinds of temporization can be created by writing storage classes with
their own .TEMP methods:
class LoudArray is Array {
method TEMP {
print "Replacing $_.id() at $(caller.location)\n";
my $restorer = .SUPER::TEMP();
return {
print "Restoring $_.id() at $(caller.location)\n";
$restorer();
};
}
}
You can also modify the behaviour of temporized code structures, by
giving them a TEMP block. As with .TEMP methods, this block is
expected to return a closure, which will be executed at the end of
the temporizing scope to restore the subroutine to its pre-temp state:
my $next = 0;
sub next {
my $curr = $next++;
TEMP {{ $next = $curr }} # TEMP block returns the closure { $next = $curr }
return $curr;
}
Wrapping
Every subroutine has a .wrap method. This method expects a single
argument consisting of a block, closure or subroutine. That argument
must contain a call to the special call function:
sub thermo ($t) {...} # set temperature in Celsius, returns old temp
# Add a wrapper to convert from Fahrenheit...
$id = &thermo.wrap( { call( ($^t-32)/1.8 ) } );
The call to .wrap replaces the original subroutine with the closure
argument, and arranges that the closure's call to call invokes the
original (unwrapped) version of the subroutine. In other words, the call to
.wrap has more or less the same effect as:
&old_thermo := &thermo;
&thermo := sub ($t) { old_thermo( ($t-32)/1.8 ) }
The call to .wrap returns a unique identifier that can later be passed to
the .unwrap method, to undo the wrapping:
&thermo.unwrap($id);
A wrapping can also be restricted to a particular dynamic scope with temporization:
# Add a wrapper to convert from Kelvin
# wrapper self-unwraps at end of current scope
temp &thermo.wrap( { call($^t + 273.16) } );
Currying
Every subroutine has an .assuming method. This method takes a series
of named arguments, whose names must match parameters of the subroutine
itself:
&textfrom := &substr.assuming(str=>$text, len=>Inf);
It returns a reference to a subroutine that implements the same behavior
as the original subroutine, but has the values passed to .assuming
already bound to the corresponding parameters:
$all = $textfrom(0); # same as: $all = substr($text,0,Inf);
$some = $textfrom(50); # same as: $some = substr($text,50,Inf);
$last = $textfrom(-1); # same as: $last = substr($text,-1,Inf);
The result of a use statement is a (compile-time) object that also has
an .assuming method, allowing the user to bind parameters in all the
module's subroutines/methods/etc. simultaneously:
(use IO::Logging).assuming(logfile => ".log");
Other Matters
Anonymous Hashes vs. Blocks
{...} is always a block/closure unless it consists of a single list, the
first element of which is either a hash or a pair.
The standard pair LIST function is equivalent to:
sub pair (*@LIST) {
my @pairs;
for @LIST -> $key, $val {
push @pairs, $key=>$val;
}
return @pairs;
}
The standard hash function takes a block, evaluates it in list context, and
constructs an anonymous hash from the resulting key/value list:
$ref = hash { 1, 2, 3, 4, 5, 6 }; # Anonymous hash
$ref = sub { 1, 2, 3, 4, 5, 6 }; # Anonymous sub returning list
$ref = { 1, 2, 3, 4, 5, 6 }; # Anonymous sub returning list
$ref = { 1=>2, 3=>4, 5=>6 }; # Anonymous hash
$ref = { 1=>2, 3, 4, 5, 6 }; # Anonymous hash
Pairs as lvalues
Pairs can be used as lvalues. The value of the pair is the recipient of the assignment:
(key => $var) = "value";
When binding pairs, names can be used to "match up" lvalues and rvalues:
(who => $name, why => $reason) := (why => $because, who => "me");
Out-of-Scope Names
$CALLER::varname specifies the $varname visible in the dynamic
scope from which the current block/closure/subroutine was called.
$MY::varname specifies the lexical $varname declared in the current
lexical scope.
$OUTER::varname specifies the $varname declared in the lexical
scope surrounding the current lexical scope (i.e. the scope in which
the current block was defined).

