Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between using Raku's Code.assuming method and using an anonymous Block or Sub?

The Raku docs say that Code.assuming

Returns a Callable that implements the same behavior as the original, but has the values passed to .assuming already bound to the corresponding parameters.

What is the difference between using .assuming and wrapping the Code in an anonymous Block (or Sub) that calls the inner function with some parameters already bound?

For instance, in the code below, what is the difference between &surname-public (an example the docs provide for .assuming) and &surname-block;


sub longer-names ( $first, $middle, $last, $suffix ) {
    say "Name is $first $middle $last $suffix";
}

my &surname-public = &longer-names.assuming( *, *, 'Public', * );
my &surname-block  = -> $a,$b,$c { longer-names($a, $b, 'Public', $c) }

surname-public( 'Joe', 'Q.', 'Jr.');  # OUTPUT: «Name is Joe Q. Public Jr.»
surname-block(  'Joe', 'Q.', 'Jr.');  # OUTPUT: «Name is Joe Q. Public Jr.»

I see that .assuming saves a bit of length and could, in some contexts, be a bit clearer. But I strongly suspect that I'm missing some other difference.

like image 283
codesections Avatar asked Mar 14 '21 15:03

codesections


1 Answers

There really isn't a difference.

While the code to implement .assuming() is almost 300 lines, the important bit is only about ten lines of code.

    $f = EVAL sprintf(
        '{ my $res = (my proto __PRIMED_ANON (%s) { {*} });
           my multi __PRIMED_ANON (|%s(%s)) {
               my %%chash := %s.hash;
               $self(%s%s |{ %%ahash, %%chash });
           };
           $res }()',
        $primed_sig, $capwrap, $primed_sig, $capwrap,
        (flat @clist).join(", "),
        (@clist ?? ',' !! '')
    );

The rest of the code in .assuming is mostly about pulling information out of the signatures.


Let's take your code and insert it into that sprintf.
(Not exactly the same, but close enough for our purposes.)

{
  my $res = (
    #  $primed_sig          v----------------------v
    my proto __PRIMED_ANON ($first, $middle, $suffix) { {*} }
  );

  # $capwrap               vv
  # $primed_sig                v----------------------v
  my multi __PRIMED_ANON (|__ ($first, $middle, $suffix)) {
    # $capwrap   vv
    my %chash := __.hash;

    #     v---------------------------v  @clist
    $self(__[0], __[1], 'Public', __[2], |{ %ahash, %chash });
  };

  # return the proto
  $res
}()

If we simplify it, and tailor it to your code

my &surname-public = {
  my $res = (
    my proto __PRIMED_ANON ($first, $middle, $suffix) { {*} }
  );

  my multi __PRIMED_ANON ( $first, $middle, $suffix ) {
    longer-names( $first, $middle, 'Public', $suffix )
  };

  $res
}()

We can simplify it further by just using a pointy block.

my &surname-public = -> $first, $middle, $suffix {
  longer-names( $first, $middle, 'Public', $suffix )
};

Also by just using single letter parameter names.

my &surname-public = -> $a,$b,$c { longer-names($a, $b, 'Public', $c) }

Like I said, there really isn't a difference.


In the future, it may be more beneficial to use .assuming(). After it gets rewritten to use RakuAST.

like image 194
Brad Gilbert Avatar answered Oct 21 '22 11:10

Brad Gilbert