Имя метода класса с ^ не вызывается должным образом

Когда я делаю метод класса, который начинается с ^, и я пытаюсь вызвать его, это дает мне ошибку.

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
Другие вопросы по тегам