Skip to content

Instantly share code, notes, and snippets.

@masak
Created August 16, 2011 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masak/1149126 to your computer and use it in GitHub Desktop.
Save masak/1149126 to your computer and use it in GitHub Desktop.
Macros and short-circuiting
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment