Имя метода класса с ^ не вызывается должным образом - PullRequest
0 голосов
/ 11 января 2019

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

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 Ответ

0 голосов
/ 11 января 2019

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
...