Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Re: A couple questions on Moose::MOP::Class

by stvn (Monsignor)
on May 03, 2011 at 02:00 UTC ( #902611=note: print w/ replies, xml ) Need Help??


in reply to A couple questions on Moose::MOP::Class

How can you have a wrapper with no modifiers?

That is referring to the base overhead of Class::MOP::Method::Wrapped, which is the object which must wrap the CODE ref in order to support the method modifiers. So that performance hit that we talk about there is the base cost for using modifiers, any actual modifiers you add onto it costs additional. Think of it like a cover charge :)

Looking at the docs for Sub::Name, I see it gives a name to a sub or a specific instance of a closure for purposes of Carp etc. telling me the correct location. Naming a function does nothing to install it into the Package, which is what is used for method dispatch. When doing dispatch, the name in the Package (symbol table) is what is used as "the" name to look up, so what does giving it a different internal name have to do with anything?

Moose and Class::MOP make a distinction between methods defined in your class, and functions imported from other modules. This is why if you import function 'foo' from module 'Foo::Bar' in your role, and then compose your role into a class, the class will not have a 'foo' method. Similarly if you query the methods of a class via the MOP, you will find that there are no imported functions in the list, even though they are still in your symbol table (assuming you are not using namespace::clean that is).

So since Perl has no real way to tell the difference between a method and a function, Moose had to devise a test for method purity. The test that was settled on was to dive deep into the B level of things and look at the names in the actual stash. If a CV structure is linked to the proper package stash then we know that it was defined in that package and we can therefore assume it is a method. If it has a different package stash name, then we assume it is imported and therefore is not a method. This works great except that Moose generates a LOT of methods and those would not, on their own, have the proper package stash name. So what Sub::Name provides is exactly that, it allows you to take a CV and assign the package stash name as well as the CV stash name.

Welcome to the twisty maze of ugliness that is making Perl 5 bend to your whim (and do so with a production-quality level of stability too).

-stvn


Comment on Re: A couple questions on Moose::MOP::Class
Re^2: A couple questions on Moose::MOP::Class
by chromatic (Archbishop) on May 03, 2011 at 02:17 UTC
    ... since Perl has no real way to tell the difference between a method and a function...

    Maybe yours doesn't, but I have a patched version of Perl 5.13 right here which does!

      How does it tell? Any sub created in the Package looks the same... how does it know you intend to call it using the arrow-notation dispatch and expect the class or instance as the first parameter?

        I added a method keyword.

Re^2: A couple questions on Moose::MOP::Class
by John M. Dlugosz (Monsignor) on May 03, 2011 at 04:47 UTC
    Re Class::MOP::Method::Wrapped: Out of curiosity, does it gather all the before/after/around stuff into one thoughtful list, or does it just keep chaining things with more single-use wrappers?

    And I was wondering... how does an 'after' method get called without having the wrapper show up in the call stack? If the original is chained to with a GOTO, it won't get control back again.

    Moose and Class::MOP make a distinction between methods defined in your class, and functions imported from other modules.
    Yea, that's what "no moose" and "autoclean" is all about. So, the method enumerator does the same thing as autoclean, and they work by comparing the name recorded in the function itself with the name it's being accessed under, to tell if it was not imported.

    Let me see if I'm following... for code that's been generated or otherwise not created using the classic 'sub' at package level, it won't record that origin and would always look like it was imported, even for generated methods like the accessors. So what that passage was trying to say is that a fully-quallified name in the Sub::Name or the natural origin of the function is used to determine if it was imported. Right?

    From reading Sub::Name, I thought that it simply records what you wanted in the same spot that a natural born sub does anyway. You talk about "B" and "stash" and other things not in my namespace, which makes me think now that the determination of the natural born name was not something it was originally meant to do. So Sub::Name is a newer thing and Carp et al. were updated to look at it, but defining a sub still doesn't populate that itself?

    Re Welcome to the twisty maze: Thanks.

      Re Class::MOP::Method::Wrapped: Out of curiosity, does it gather all the before/after/around stuff into one thoughtful list, or does it just keep chaining things with more single-use wrappers?

      No, the Class::MOP::Method::Wrapped object keeps 3 ordered lists, one of befores, one of arounds and one of afters and it makes sure to apply them in the order you defined them. The docs actually go into a lot of detail about how this works.

      And I was wondering... how does an 'after' method get called without having the wrapper show up in the call stack?

      It does show up actually, they are named ":before", ":around" and ":after", here is a comment from the source explaining some of this:

      # NOTE: # the methods above used to be named like this: # ${pkg}::${method}:(before|after|around) # but this proved problematic when using one modifier # to wrap multiple methods (something which is likely # to happen pretty regularly IMO). So instead of naming # it like this, I have chosen to just name them purely # with their modifier names, like so: # :(before|after|around) # The fact is that in a stack trace, it will be fairly # evident from the context what method they are attached # to, and so don't need the fully qualified name.

      If the original is chained to with a GOTO, it won't get control back again.

      It isn't done with GOTO actually, for exactly that reason, it is all quite controlled. If you look at the source you will see the $_build_wrapped_method method which does much of the dirty work.

      o, the method enumerator does the same thing as autoclean, ...

      Yes, but the method enumerator did it long before autoclean existed and way before autoclean was stable/sane.

      Let me see if I'm following... for code that's been generated or otherwise not created using the classic 'sub' at package level, it won't record that origin and would always look like it was imported, even for generated methods like the accessors. So what that passage was trying to say is that a fully-quallified name in the Sub::Name or the natural origin of the function is used to determine if it was imported. Right?

      Yes, but Sub::Name alters the internal (C-level) structure of the CV data structure to basically add the fully-qualified name. It then appears just as if it was originally defined in that package.

      You talk about "B" and "stash" and other things not in my namespace, ...

      B is the "The Perl Compiler Backend", it is a way to access all the C-level data structures from Perl. The "stash" is the name for an element of those data structures, specifically the place where I go to find the actual fully-qualified name of the sub.

      ... which makes me think now that the determination of the natural born name was not something it was originally meant to do.

      Right, we had to get all sneaky and use XS to get at this stuff, it is not normally exposed in Perl.

      So Sub::Name is a newer thing and Carp et al. were updated to look at it, but defining a sub still doesn't populate that itself?

      No, Sub::Name alters the underly C-level structure such that when Carp gets to it,... it is just there. No changes had to be made to other modules.

      -stvn

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://902611]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (8)
As of 2014-08-22 08:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (150 votes), past polls