TL; DR Метод вызывается правильно. ^
в foo.^bar
обозначает «метаметод». Это не метод экземпляра и не метод класса. Метаметоды передаются как инвокант, как в случае со всеми методами, и еще один объект «оригинальный инвокант» в качестве первого аргумента.
Большинству пользователей никогда не придется думать об этом. Но вы спросили, так что давайте копаться в ...
метаметоды
Цитирование Мета-объектного протокола (MOP) Страница документа P6:
Perl 6 построен на уровне мета-объектов.
Этот слой MOP определяет различные встроенные «метаметоды», которые вы можете использовать.
Например:
say .^attributes given class bar { has Int $!foo }
Отображается (Int $!foo)
. Вызов метода .^attributes
является метаметодом. Он вызывается (обычно невидимым) метаобъектом, который определяет, как работает тип P6 за кулисами. В этом случае он возвращает атрибуты (has
переменных) класса.
Но могут быть и метаметоды, определенные пользователем. Один из способов объявить это в обычном классе:
say .^attributes given class baz { has Int $!foo; method ^attributes ($arg) { self, $arg } }
Приведенный выше класс baz
включает в себя объявление метаметода ^attributes
, которое переопределяет встроенный метаметод. Особо следует отметить, что я добавил аргумент. ВСЕ метаметоды получают как минимум один аргумент (в дополнение к обычному инвоканту).
С помощью этого объявления вместо (Int $!foo)
в ответ на вызов .^attributes
вы получите список self, $arg
из .^attributes
метода в baz
классе.
Обратите внимание, что self
не является ни экземпляром baz
, ни объектом типа baz
- вместо этого Perl6::Metamodel::ClassHOW+{<anon>}.new
- тогда как $arg
- a baz
(тип) объект.
Остальная часть этого ответа объясняет, что происходит более подробно.
Резюме обычного вызова метода
Во-первых, давайте вспомним типичный вызов метода.
Синтаксис foo.bar
приводит к отправке метода (сообщения) "bar" в foo
.
Если foo
является экземпляром класса, «bar» отправляется этому экземпляру. Такой вызов метода иногда называют «методом экземпляра».
Если foo
- это объект типа , соответствующий классу, "bar" отправляется этому объекту типа. Такой вызов метода иногда называют «методом класса».
В обоих случаях "bar" отправляется на foo
.
foo.^bar
Синтаксис foo.^bar
отличается.
Считайте ^
как указывающий на другой объект, который невидимо парит над foo
, или что-нибудь действительно связанное с kind типа foo
is.
Такими объектами являются HOW
объекты, которые определяют, как работают объекты. Эти HOW
объекты обычно остаются невидимыми, благодаря чему все работает хорошо, а пользователи блаженно не знают о своем существовании и работе, которую они выполняют. 1
Вызов метода foo.^bar
обычно приводит к тому, что P6 отправляет вызов метаметода в foo
HOW
объект.
Эти метаметоды требуют двух аргументов, подобных инвокантам. Там есть объект HOW
. Это передается как обычный инвокант. Тогда есть объект foo
. Это передается в качестве первого обычного аргумента метаметоду.
Так вот, что обычно происходит, когда вы вызываете foo.^bar
- вызов метаметода отправляется объекту foo
HOW
, а foo
передается как обычный аргумент, хранящий то, что можно назвать " Оригинальный инвокант ".
foo.^bar
при отсутствии встроенного .^bar
метаметода
Если вы позвоните foo.^bar
, когда такого метода нет, вы получите ошибку:
42.^bar
выходы:
No such method 'bar' for invocant of type 'Perl6::Metamodel::ClassHOW'
Обратите внимание, что тип инвоканта является классом метамодели, а не 42
или Int
.
Если определенный пользователем класс объявляет ^.bar
, то P6 вызывает его, передавая объект HOW
экземпляра / класса в качестве инвоканта и "оригинальный инвокант" (foo
) в качестве первого обычного аргумента:
class foo {
method ^bar ($arg) { self, $arg }
}
say foo.^bar; # (Perl6::Metamodel::ClassHOW+{<anon>}.new (foo))
Сноска
1 Вызов .HOW
для объекта возвращает его HOW
:
say .HOW given class {} # Perl6::Metamodel::ClassHOW
HOW
объекты являются частью MOP , слоя глубоко внутри P6.
Большинству разработчиков никогда не понадобится явно копать до этого уровня.
Если вы копаете еще глубже, вы оставляете указанный P6. В Rakudo .HOW
объекта HOW
обычно является NQP объектом:
say ((.HOW.new given class {}).HOW).^name; # NQPClassHOW