Почему я не могу вызвать мета-методы в Routine::WrapHandle?

Это постоянный вопрос из моего предыдущего. Почему метод развёртывания в Perl 6 является рутинным методом?, но в основном не связано.

wrap задокументировано, что метод возвращает "экземпляр частного класса с именем WrapHandle. Кроме того, что он странен для утечки частного класса, это не название возвращаемой вещи. Класс на самом деле Routine::WrapHandle:

$ perl6
> sub f() { say 'f was called' }
sub f () { #`(Sub|140397740886648) ... }
> my $wrap-handle = &f.wrap({ say 'before'; callsame; say 'after' });
Routine::WrapHandle.new

Но вот вопрос. Я хотел позвонить .^methods на Routine::WrapHandle, Это не работает:

> Routine::WrapHandle.^methods
Could not find symbol '&WrapHandle'
  in block <unit> at <unknown file> line 1

Это то же самое, что пытаться использовать неопределенное имя класса:

> Foo::Baz.^methods
Could not find symbol '&Baz'
  in block <unit> at <unknown file> line 1

Я могу вызвать мета-методы на экземпляре, хотя:

> $wrap-handle.^methods
(restore)
> $wrap-handle.^name
Routine::WrapHandle

Что там происходит?

1 ответ

Решение

Определение Routine::WrapHandle выглядит примерно так:

my class Routine {
    method wrap(&wrapper) {
        my class WrapHandle { ... }
        ...
    }
}

Мы можем игнорировать окружающий метод; важно то, что мы имеем дело с лексическим внутренним классом, определенным внутри внешнего класса. Упрощая еще немного, мы приходим к следующей схеме:

package Foo {
    my class Bar {}
    say Bar.^name; #=> Foo::Bar
}

say try Foo::Bar; #=> Nil

Полное имя внутреннего класса будет включать имя включающего пакета, но из-за явного my (вместо неявного our), класс не будет установлен как переменная пакета, и поиск в области видимости файла завершится неудачно.

Другие вопросы по тегам