Home > Perl6 > I left my keys in a side-channel

I left my keys in a side-channel

While trying to bake option groups into a module I stumbled over a neat solution to a common problem. I wanted to have a subroutine as a where-clause that slurps up named arguments, does some checks and either returns True to satisfy the where-clause or to die with a proper error message. That was simple but incomplete. The where-clause doesn’t provide the name of the argument it is checking on, what would be needed to have a proper error message. Let’s have some (simplified) code.

sub checker(*%colon-keys){ sub ($value-from-where-clause) { True } }
sub f( *%h where checker(:a, :b, :c) ) {}

The sub checker is called before the where clause is actually checking anything. In Perl6 a where-clause is kind of syntaxy. If an expression is provided it will call that expression and keep it’s returned value to then go and do the actual check against the value of %h. This does not happen at compile time and the returned value is not cached. In our example an anonymous sub is returned that takes one argument (a requirement by where) and must return True to let the where-clause-check pass.

As you can see checker takes a list of colon-pairs. That leaves the question how we can provide additional information we might want to output in an exception, esp. if we want that parameter to be optional and avoid odd syntax. We could have an optional positional but then we can’t mix positional and named arguments in checker. Storing that value would be trivial because the anonymous sub that is returned could have a closure variable. We just need to fill it. Luckily the sub is returned as a reference that is then called by the where-clause. We can sneak another call in, as long as we we don’t forget to return the code reference to the anonymous sub.

Returning a reference to the same object is done by chainable method calls. Often, when things get complicated in Perl 6-land, we just mix a role in. Then we have a method and can return self.

use v6;

sub g($i){
    my $closure-variable;
    sub ($value-from-where-clause) {
        say [$closure-variable, $value-from-where-clause];
        $value-from-where-clause == $i
            or die "bad value $value-from-where-clause for $closure-variable"
    } but role :: {
        method side-channel($second-value){
            $closure-variable = $second-value;
            self
    }
  }
}

sub f($a where g(42).side-channel($a.VAR.name) ){ 'OK' }

say f(42);
# OUTPUT
# [$a 42]
# OK

And there we have it — a side-channel to a where-clause-call or any other spot we can use higher order functions at. Now I can go and provide MTA error messages for option groups.

Advertisements
Categories: Perl6
  1. No comments yet.
  1. September 26, 2016 at 23:05

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: