Имя метода класса с ^ не вызывается должным образом
Когда я делаю метод класса, который начинается с ^
, и я пытаюсь вызвать его, это дает мне ошибку.
class C {
method ^test () {
"Hi"
}
}
dd C.new.test;
Too many positionals passed; expected 1 argument but got 2
in method test at .code.tio line 1
in block <unit> at .code.tio line 1
Если я сделаю тот же метод без ведущих ^
работает нормально.
class C {
method test () {
"Hi"
}
}
dd C.new.test;
"Hi"
Я видел, как модули предоставляют классы с методами, которые начинаются с ^
, что приводит к моему вопросу. Почему я получаю эту ошибку, когда определяю имя метода, начинающееся с ^
?
1 ответ
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
это baz
(тип) объект.
Остальная часть этого ответа объясняет, что происходит более подробно.
Резюме обычного вызова метода
Во-первых, давайте повторим типичный вызов метода.
Синтаксис foo.bar
приводит к отправке метода (сообщения) "bar" foo
,
Если foo
является экземпляром класса, "bar" отправляется этому экземпляру. Такой вызов метода иногда называют "методом экземпляра".
Если foo
это тип объекта, соответствующий классу, "бар" отправляется этому объекту типа. Такой вызов метода иногда упоминается как "метод класса".
В обоих случаях "бар" отправляется foo
,
foo.^bar
Синтаксис foo.^bar
это отличается.
Прочитайте ^
как указывая на другой объект, который невидимо парит над foo
или вообще что-нибудь связанное с типом foo
является.
Такие объекты HOW
объекты, которые определяют, как работают объекты. Эти HOW
объекты, как правило, остаются невидимыми, благодаря чему все работает хорошо, а пользователи блаженно не знают о своем существовании и работе, которую они выполняют. 1
Вызов метода формы foo.^bar
обычно приводит к тому, что P6 отправляет вызов метаметода foo
"s HOW
объект.
Эти метаметоды требуют два аргумент-подобных аргумента. Там есть HOW
объект. Это передается как обычный инвокант. Тогда есть foo
объект. Это передается в качестве первого обычного аргумента метаметоду.
Так вот, что обычно происходит, когда вы звоните foo.^bar
- вызов метаметода отправляется foo
"s 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. В Ракудо .HOW
из HOW
Объект, как правило, является объектом NQP:
say ((.HOW.new given class {}).HOW).^name; # NQPClassHOW