How do I take a reference to new?

The error message is indeed confusing.

The :with parameter expects a Callable. Card.new is not a Callable. If you write it as :with( { Card.new($^number, $^suit) } ), it appears to work.

Note that I did not use $^value, $^suit, because they order differently alphabetically, so would produce the values in the wrong order. See The ^ twigil for more information on that syntax.

The error is LTA, this makes it a little bit better.

To get back to your question: you can find the code object that corresponds to Card.new with ^find_method. However, that will not work, as Card.new actually expects 3 arguments: the invocant (aka self), $value and $suit. Whereas the cross function will only pass the value and the suit.


The title of your question is “How do I take a reference to new?”, but that is not really what you want to do.

Raku being Raku, you can actually get a reference to new.

my $ref = Card.^lookup('new');

You can't use it like you want to though.

$ref(2,'Clubs'); # ERROR

The problem is that methods take a class or instance as the first argument.

$ref(Card, 2,'Clubs');

You could use .assuming to add it in.

$ref .= assuming(Card);
$ref(2,'Clubs');

But that isn't really any better than creating a block lambda

$ref = { Card.new( |@_ ) }
$ref(2,'Clubs');

All of these work:

cross( @values, @suits ) :with({Card.new(|@_)})   # adverb outside
cross( @values, @suits,  :with({Card.new(|@_)}) ) # inside at end
cross( :with({Card.new(|@_)}), @values, @suits )  # inside at beginning


@values X[&( {Card.new(|@_)} )] @suits # cross meta-op with fake infix op


do {
    sub new-card ($value,$suit) { Card.new(:$value,:$suit) }
    @values X[&new-card] @suits
}

do {
    sub with ($value,$suit) { Card.new(:$value,:$suit) }
    cross(@values,@suits):&with
}