TL;DR The method is getting invoked properly. The ^
in foo.^bar
indicates a "metamethod". This is neither an instance method nor a class method. Metamethods are passed both an invocant, as is the case for all methods, and another "original invocant" object as the first argument.
Most users will never need to think about this stuff. But you've asked, so let's dig in...
Metamethods
Quoting the Meta-object protocol (MOP) Raku doc page:
Raku is built on a meta object layer.
This MOP layer defines various built in "metamethods" that you can use.
For example:
say .^attributes given class bar { has Int $!foo }
This displays (Int $!foo)
. The .^attributes
method call is a metamethod. It's called on the (typically invisible) metaobject that determines how a Raku type works behind the scenes. In this case, it returns the attributes (has
variables) of a class.
But there can also be user defined metamethods. One way to declare these is in an otherwise ordinary class:
class {
has Int $!foo;
method ^attributes ($arg) { self, $arg }
}
say baz.^attributes
The above baz
class includes an ^attributes
metamethod declaration that overrides the built in metamethod. Of special note, I've added an argument. ALL metamethods get at least one argument (in addition to a regular invocant).
With this declaration, instead of (Int $!foo)
in response to an .^attributes
call you instead get the list self, $arg
from the .^attributes
method in the baz
class.
Note how self
is neither a baz
instance object nor a baz
type object -- instead it's Perl6::Metamodel::ClassHOW+{<anon>}.new
-- whereas $arg
is a baz
(type) object.
The rest of this answer explains what's going on in more detail.
A recap of an ordinary method call
First, let's recap a typical method call.
The syntax foo.bar
results in a "bar" method (message) being dispatched to foo
.
If foo
is an instance of a class, "bar" is dispatched to that instance. Such a method call is sometimes referred to as an "instance method".
If foo
is a type object corresponding to a class, "bar" is dispatched to that type object. Such a method call is sometimes referred to as a "class method".
In both cases, "bar" is dispatched to foo
.
#foo.^bar
The syntax foo.^bar
is different.
Read the ^
as pointing up to another object that hovers invisibly above foo
, or indeed anything related to the kind of type foo
is.
Such objects are HOW
objects that determine How Objects Work. These HOW
objects typically stay invisible, making things work nicely, with users blissfully unaware of their existence and the work they're doing.1
A method call of the form foo.^bar
ordinarily results in Raku dispatching a metamethod call to foo
's HOW
object.
These metamethods require two invocant-like arguments. There's the HOW
object. This is passed as the regular invocant. Then there's the foo
object. This is passed as a first ordinary argument to the metamethod.
So that's what ordinarily happens when you call foo.^bar
-- a metamethod call is dispatched to foo
's HOW
object and foo
is passed as an ordinary argument storing what could be said to be "the original invocant".
#foo.^bar
when there's no built in .^bar
metamethod
If you call foo.^bar
when there's no such method you'll get an error:
42.^bar
yields:
No such method 'bar' for invocant of type 'Perl6::Metamodel::ClassHOW'
Note how the invocant type is a metamodel class, not 42
or Int
.
If a user defined class declares a ^.bar
, then Raku calls it, passing the instance/class's HOW
object as the invocant and the "original invocant" (foo
) as the first ordinary argument:
class foo {
method ^bar ($arg) { self, $arg }
}
say foo.^bar; # (Perl6::Metamodel::ClassHOW+{<anon>}.new (foo))
Footnotes
1 Calling .HOW
on an object returns its HOW
:
say .HOW given class {} # Perl6::Metamodel::ClassHOW
HOW
objects are part of the MOP, a layer deep down inside Raku.
Most devs will never need to explicitly dig down to this level.
If you dig even deeper you're leaving specified Raku. In Rakudo the .HOW
of a HOW
object is typically an NQP object:
say ((.HOW.new given class {}).HOW).^name; # NQPClassHOW