public
Created

Macros and short-circuiting

  • Download Gist
macros-and-short-circuiting.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
So, let's say we want to define infix:<&&> using a macro. The reason we can't
just use a sub infix:<&&> is this:
 
* arguments to subs are evaluated before the call is made
* infix:<&&> is *short-circuiting*, which means that the rhs argument shouldn't
be evaluated until it turns out to be necessary to evaluate it
 
Macros don't have the problem of premature evaluation. The arguments are sent
in as ASTs:
 
macro foo($x) {
say $x.WHAT;
say $x.perl;
}
foo "OH " ~ "HAI";
 
The above will output something like this:
 
Perl6::AST::Node
Perl6::AST::Node.new(
"call",
:name<< infix:<~> >>,
:args(
Perl6::AST::Node.new(
"literal",
:contents("OH ")
),
Perl6::AST::Node.new(
"literal",
:contents("HAI")
)
)
)
 
(Modulo the exact nature of the as yet unspecified one Perl 6 AST API to rule
them all.)
 
So you see, things are passed in not as values, but as AST clades. At the time
they're passed in, they haven't been evaluated. This is what we want for short-
circuiting operators.
 
 
So, let's implement infix:<&&>:
 
macro infix:<&&>($lhs, $rhs) {
quasi {
my Mu $lhs-bound := {{{ $lhs }}};
do if $lhs-bound {
{{{ $rhs }}}
}
else {
$lhs-bound
}
}
}
 
We need to bind the $lhs because we're using it twice. The $rhs only gets
evaluated if the $lhs evaluates to true -- short-circuiting.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.