Сведение проблемы к MRE:
class foo {}
say(foo.new); # Cannot stringify ...
Упрощение решения:
class foo { method Str () { 'foo' } }
say(foo.new); # foo
Таким образом, добавьте метод Str
.
Звучит просто, но нужно учесть / объяснить множество закулисных вещей.
nqp против раку
Вышеупомянутое решение - это та же техника, которую использует раку; когда подпрограмма / операция ожидает, что значение будет строкой, но не является, поведение языка заключается в попытке принуждения к строке. В частности, посмотрите, есть ли Str
метод, который можно вызвать для значения, и если да, вызовите его.
В этом случае NQP NQPMu
, который является более простым чем Mu
raku по умолчанию, Str
метод. Итак, решение - добавить его вручную.
В целом, NQP - довольно враждебный язык, если вы не знаете раку достаточно хорошо и не прошли через Курс по внутреннему устройству Rakudo и NQP.
И как только вы освоите материал этого курса, я рекомендую вам рассмотреть каналы IRC # raku-dev и / или #moarvm в качестве вашего первого порта захода, а не SO (если ваша цель не заключается конкретно в увеличении покрытия SO для nqp / moarvm).
Отладка кода компилятора
Как вы увидите, связанный код NQP вызывает .say
дескриптор файла.
Затем вызывается этот метод.
Тело этого метода - $str ~ "\n"
. Этот код попытается преобразовать $str
в строку (точно так же, как это было бы в raku). Вот что приведет к ошибке «Невозможно преобразовать в строку».
Поиск по запросу «Невозможно преобразовать в строку» в репозитории NQP совпал только с некоторым кодом Java. Бьюсь об заклад, вы не используете Rakudo на JVM. Это означает, что сообщение об ошибке должно исходить от MoarVM.
Тот же поиск в репозитории MoarVM дает MoarVM.
Оглядываясь назад на процедуру, содержащую эту строку, мы видим :
/* Check if there is a Str method. */
MVMROOT(tc, obj, {
strmeth = MVM_6model_find_method_cache_only(tc, obj,
tc->instance->str_consts.Str);
});
Это показывает, что серверная часть, написанная на C, ищет и вызывает «метод» с именем Str
. (Он полагается на внутренний API (модель 6), которому соответствуют все три уровня компилятора (raku, nqp и backends).)
Настройка метода Str
Вам нужно будет соответствующим образом настроить метод Str
. Например, чтобы напечатать имя класса, если это объект типа, и значение его атрибута $!bar
в противном случае:
class foo {
has $!bar;
method Str () { self ?? nqp::coerce_is($!bar) !! self.HOW.name(self) }
}
say(foo.new(bar=>42)); # 42
Несмотря на название метода, подпрограмма nqp say
не ожидает raku Str
, а скорее нативную строку nqp (которая в конечном итоге является нативной строкой MoarVM на бэкэнде MoarVM). Отсюда необходимость в nqp::coerce_is
(который я обнаружил, просмотрев документ nqp ops а>).
self.HOW.name(self)
- еще один пример того, что в nqp просто нет таких тонкостей, как у raku. Вы можете написать тот же код на raku, но идиоматический способ написать его на raku - self.^name
.
person
raiph
schedule
19.03.2020