Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I call meta methods on Routine::WrapHandle?

Tags:

raku

This is a continuing question from my previous one Why is Perl 6's unwrap method a method of Routine?, but mostly unrelated.

The wrap method is documented to return "an instance of a private class called WrapHandle. Besides that being odd for leaking a class that's private, it's not actually the name of the thing that comes back. The class is actually 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

But here's the question. I wanted to call .^methods on Routine::WrapHandle. That doesn't work:

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

This is the same as trying it on an undefined class name:

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

I can call meta methods on the instance though:

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

What's going on there?

like image 823
brian d foy Avatar asked May 05 '17 19:05

brian d foy


1 Answers

The definition of Routine::WrapHandle looks something like this:

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

We can ignore the surrounding method; the important bit is that we're dealing with a lexical inner class defined within an outer class. Simplifying some more, we arrive at the following pattern:

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

say try Foo::Bar; #=> Nil

The fully qualified name of the inner class will include the name of the enclosing package, but due to the explicit my (instead of the implicit our), the class will not be installed as a package variable and the lookup at file scope fails.

like image 82
Christoph Avatar answered Oct 02 '22 03:10

Christoph