=begin pod :kind("Type") :subkind("class") :category("basic")

=TITLE class WhateverCode

=SUBTITLE Code object constructed by Whatever-currying

    class WhateverCode is Code { }

C<WhateverCode> objects are the result of L<Whatever|/type/Whatever>-currying.
See the L<Whatever|/type/Whatever> documentation for details.

When you wish to control how a method or function interprets any I<Whatever
star>, you may use multi dispatch with C<Whatever> and C<WhateverCode>
parameters to do so, as in the following example:

    class Cycle {
          has $.pos;
          has @.vals;
    }

    multi sub get-val(Cycle $c, Int $idx) {
          $c.vals[$idx % $c.vals.elems]
    }

    # Define what to do with a stand-alone * as the second argument
    multi sub get-val(Cycle $c, Whatever $idx) {
        get-val($c, $c.pos);
    }

    # Define what to do with a * WhateverCode in an expression
    multi sub get-val(Cycle $c, WhateverCode $idx) {
        get-val($c, $idx($c.pos));
    }

    my Cycle $c .= new(:pos(2), :vals(0..^10));

    say get-val($c, 3);   # OUTPUT: «3␤»
    say get-val($c, *);   # OUTPUT: «2␤»
    say get-val($c, *-1); # OUTPUT: «1␤»

The C<WhateverCode> C<does> the L<Callable|/type/Callable> role, so it should be
possible to introspect the type of C<Callable> it contains; for instance,
continuing the previous example, we can add a multi that handles a
C<WhateverCode> with two arguments via checking the signature:

=begin code :skip-test<compile time error>
# Define what to do with two * in an expression
multi sub get-val(Cycle $c, WhateverCode $idx where { .arity == 2 }) {
    get-val($c, $idx($c.pos, $c.vals.elems));
}

say get-val($c, * + * div 2); # 2 + 10/2 = 7
=end code

Note, though, that subexpressions may impose their own I<Whatever star>
rules:

=for code :skip-test<compile time error>
my @a = (0, 1, 2);
say get-val($c, @a[*-1]) # 2, because the star belongs to the Array class

This can make the ownership of I<Whatever stars> become confusing rather
quickly, so be careful not to overdo it.

You may instead type-constrain using L<Callable|/type/Callable> type in order to
accept any C<Callable>, including C<WhateverCode>:

    sub run-with-rand (Callable $code) { $code(rand) };
    run-with-rand *.say;           # OUTPUT: «0.773672071688484␤»
    run-with-rand {.say};          # OUTPUT: «0.38673179353983␤»
    run-with-rand sub { $^v.say }; # OUTPUT: «0.0589543603685792␤»

Type-constraining with C<&>-sigiled parameter works equally well and is shorter
to type:

    sub run-with-rand (&code) { code time };

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
