Home > Raku > Spying on return

Spying on return

Matthew Stuckwisch wrote a module to help with spying on return values. That made me wonder if one could wrap return.

&return.wrap: -> \c { say c; CX::Return.new.throw }
sub s { return 42; }
s;

Output:

42
True
===SORRY!===
control exception without handler
Nil
Some exceptions were thrown in END blocks:
3
Unhandled exception: Too many positionals passed; expected 1 argument but got 2
   at SETTING::src/core.c/Exception.pm6:510  (/usr/local/src/rakudo/install/share/perl6/runtime/CORE.c.setting.moarvm:print_exception)
 from SETTING::src/core.c/Exception.pm6:566  (/usr/local/src/rakudo/install/share/perl6/runtime/CORE.c.setting.moarvm:)

That made me laugh, because Rakudo actually tried to do what I asked it to. By wrapping return we globally change that function. It can’t work because the control exception is thrown in the wrong block. But it doesn’t blow up completely because CORE doesn’t use return.

Since return is an ordinary Sub, there must be a way to throw in the right context.

my &return = -> \c {
    say c;
    use nqp;
    nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, nqp::p6recont_ro(c));
}

sub s { return 42; }
s;

# OUTPUT: 42

That works, is neat but not very helpful. Most routines don’t use a return-statement. To get hold of any return value, we need to wrap the Callable in question. We can use a trait for that.

sub trait_mod<is>:(Callable $c, :$return-spy!) {
    $c.wrap: sub (|c) {
        my \ret = callsame;
        say sprintf('%s(%s): %s', $c.name, c, ret) if $*debug;
        return-rw ret
    };
}

sub f is return-spy { 42 }
my $*debug = True;
f;

# OUTPUT: 42

We could move the conditional of $*debug out of the wrapper to avoid the runtime penalty if no debugging is needed. I’m not sure if that would work well with precomp though. Please note the return-rw.

sub b(\c) { return-rw c }
my $c = 1;
b($c)++; # this won't work without return-rw
say $c;
# OUTPUT: 2

With a simple return, even a sigilless argument will not maintain the container. In fact, using return-rw is almost always required for debugging subs. I left a note with Matthew.

Categories: Raku
  1. No comments yet.
  1. December 14, 2020 at 20:06

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

%d bloggers like this: