Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
173 lines (130 sloc) 6.16 KB
=begin pod :tag<perl6>
=TITLE Contexts and contextualizers
=SUBTITLE What are contexts and how to get into them
A context is needed, in many occasions, to interpret the value of a container.
In Perl 6, we will use context to coerce the value of a container into some type
or class, or in general decide what to do with it, as in the case of the sink
=head1 Sink X<|sink context>
The I<sink> context is equivalent to what in other languages is called C<void>
context, that is, a context in which we throw (down the sink, as it were) the
result of an operation or the return value from a block. In general, this
context will be invoked in warnings and errors when a statement does not know
what to do with that value.
=begin code
my $sub = -> $a { return $a² };
$sub; # OUTPUT: «WARNINGS:␤Useless use of $sub in sink context (line 1)␤»
=end code
You can force that sink context on L<Iterator|/type/Iterator>s, by
using the L<C<sink-all>|/routine/sink-all> method. L<Proc|/type/Proc>s can also
be L<sunk via the C<sink> method|/type/Proc#method_sink>, forcing them to raise
an exception and not returning anything.
In general, blocks will warn if evaluated in sink context; however,
L<gather/take blocks|/language/control#Flow%29_gather_take> are explicitly
evaluated in sink context, with values returned explicitly using C<take>;
however, sinking will explicitly throw away those values, so use sink only if
you want to run a C<gather> statement for the side effects.
In sink context, an object will call its C<sink> method if present:
=begin code
sub foo {
return [<a b c>] does role {
method sink { say "sink called" }
foo; # OUTPUT: sink called
=end code
=head1 Number X<|number context>
This context, and probably all other contexts except I<sink> above, are
I<conversion> or I<interpretation> contexts in the sense that they take an
untyped or typed variable and duck-type it to whatever is needed to perform the
operation. In some cases that will imply a conversion (from L<Str|/type/Str> to
L<Numeric|/type/Numeric>, for instance); in other cases simply an interpretation
(L<IntStr|/type/IntStr> will be interpreted as L<Int|/type/Int> or as
I<Number context> is called whenever we need to apply a numerical operation on a
=begin code
my $not-a-string="1 ";
my $neither-a-string="3 ";
say $not-a-string+$neither-a-string; # OUTPUT: «4␤»
=end code
In the code above, strings will be interpreted in numeric context as long as
there are only a few digits and no other characters. It can have any number of
leading or trailing whitespace, however.
Numeric context can be forced by using arithmetic operators such as C<+> or
C<->. In that context, the L<C<Numeric>|/routine/Numeric> method will be called
if available and the value returned used as the numeric value of the object.
=begin code
my $t = True;
my $f = False;
say $t+$f; # OUTPUT: «1␤»
say $t.Numeric; # OUTPUT: «1␤»
say $f.Numeric; # OUTPUT: «0␤»
my $list= <a b c>;
say True+$list; # OUTPUT: «4␤»
=end code
In the case of I<listy> things, the numeric value will be in general equivalent
to C<.elems>; in some cases, like
L<Thread|/routine/Numeric#(Thread)_method_Numeric> it
will return an unique thread identifier.
=head1 String X<|string context>
In a I<string context>, values can be manipulated as strings. This context is
used, for instance, for coercing non-string values so that they can be printed
to standard output.
=for code :preamble<my $very-complicated-and-hairy-object>
put $very-complicated-and-hairy-object; # OUTPUT: something meaningful
Or when smartmatching to a regular expression:
put 333444777 ~~ /(3+)/; # OUTPUT: «「333」␤ 0 => 「333」␤»
In general, the L<C<Str> routine|/routine/Str> will be called on a variable to
contextualize it; since this method is inherited from L<Mu|/type/Mu>, it is
always present, but it is not always guaranteed to work. In some core classes it
will issue a warning.
L<C<~>|/routine/~> is the (unary) string contextualizer. As an operator, it
concatenates strings, but as a prefix operator it becomes the string context
=begin code
my @array = [ [1,2,3], [4,5,6]];
say ~@array; # OUTPUT: «1 2 3 4 5 6␤»
=end code
This will happen also in a
context, when C<[~]> is applied to a list
say [~] [ 3, 5+6i, Set(<a b c>), [1,2,3] ]; # OUTPUT: «35+6ic a b1 2 3␤»
In that sense, empty lists or other containers will stringify to an empty
say [~] [] ; # OUTPUT: «␤»
Since L<C<~> acts also as buffer concatenation operator|/routine/~#(Operators)_infix_~>,
it will
have to check that every element is not empty, since a single empty buffer in
string context will behave as a string, thus yielding an error.
say [~],0x33),,0x22);
# OUTPUT: «Buf:0x<03 33 02 22>␤»
=begin code
my $non-empty =, 0x33);
my $empty = [];
my $non-empty-also =,0x22);
say [~] $non-empty, $empty, $non-empty-also;
# OUTPUT: «Cannot use a Buf as a string, but you called the Stringy method on it
=end code
Since C<~> is putting in string context the second element of this list,
L<C<~>|/routine/~#(Operators)_infix_~> is going to be
using the second form that applies to strings, thus yielding the shown error.
Simply making sure that everything you concatenate is a buffer will avoid this
=for code
my $non-empty =, 0x33);
my $empty =;
my $non-empty-also =,0x22);
say [~] $non-empty, $empty, $non-empty-also; # OUTPUT: «Buf:0x<03 33 02 22>␤»
In general, a context will coerce a variable to a particular type by calling the
contextualizer; in the case of mixins, if the context class is mixed in, it will
behave in that way.
my $described-number = 1i but 'Unity in complex plane';
put $described-number; # OUTPUT: «Unity in complex plane␤»
C<but> creates a mixin, which endows the complex number with a C<Str> method.
C<put> contextualizes it into a string, that is, it calls C<Str>, the string
contextualizer, with the result shown above.
=end pod
# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
You can’t perform that action at this time.