Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Detecting which class a method is defined in

by yngwi (Initiate)
on Apr 02, 2011 at 13:56 UTC ( [id://897088]=perlquestion: print w/replies, xml ) Need Help??

yngwi has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

I've been trying to search for a solution to this for days; any help would be appreciated. Basically, I have a series of classes inheriting from each other, for example, class B is a subclass of class A, and class C is a subclass of class B.

There is an A->source() method defined, which may be overridden in class B. Now in a separate method defined in class A, say:

sub readsource { my $Class = shift; ... $Class->source(); }

So in this method I would like to know in which class the call to $Class->source() will find the source() method.

That is, if source() is not overridden in class B, then calling C->readsource() should know that it accesses A->source() when it calls C->source(). But if source() is overridden, then it should know that it uses B->source().

I would use this information in readsource() to create a new method in the class where I've found source(), a bit like what happens in Class::Data::Inheritable (which appears to use closures to remember where the accessor was defined).

Is there a way to do this without manually parsing the @ISA of all the classes involved?

Replies are listed 'Best First'.
Re: Detecting which class a method is defined in
by merlyn (Sage) on Apr 02, 2011 at 16:49 UTC
    I don't think you're getting OO yet. If you have to introspect that much, you probably aren't building actual subclasses, but rather something like plugins (HAS-A vs IS-A). If designed properly, you should just call $self->source, and it'll Do The Right Thing.

    -- Randal L. Schwartz, Perl hacker

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

      Let me add that source() is intended to be a class method (essentially an inheritable constant), and that the goal would be to create new class methods storing additional data derived from source() at the points in the class hierarchy where source() is defined or re-defined.

      It is true that the system could be redesigned to handle this better. But I was primarily interested in whether the information where Perl ultimately finds a method is accessible.

      what you're saying is if he's developing a low level or mid level tool, or something for developers, he should forget about it. hey look two of us can ignore a post and offer incorrect conjecture
Re: Detecting which class a method is defined in
by Khen1950fx (Canon) on Apr 02, 2011 at 18:10 UTC
    The way that you setup your question seemed to me to be a perfect fit for Method::Specialize and Moose, so I experimented with this. I'll leave it up to you to develop your readsource method:
    #!/usr/bin/perl use strict; use warnings; use Method::Specialize; use Moose::Util; my $cached = 0; my $gen = 0; { package RoleA; use Moose::Role; sub sourceA { print "Testing sourceA\n";} sub readsource { print "RoleA contains sourceA\n";} package RoleB; use Moose::Role; sub sourceB { } package RoleC; use Moose::Role; sub sourceC { } package Class; use Moose; with qw(RoleA); ::specializing_method source => sub { my $class = shift; my $meta = Class::MOP::Class->initialize($class); my %roles = map { $_->name = undef } map { Class::MOP::Class->initialize($_)->calculate_all_rol +es } $meta->linearized_isa; ++$gen; return sub { my ( $class, $role ) = @_; ++$cached; exists $roles{$role}; } }; package Method; use Moose; extends qw(Class); } Method->readsource;
Re: Detecting which class a method is defined in
by educated_foo (Vicar) on Apr 03, 2011 at 16:13 UTC
    If you don't mind delving into a bit of dark magic, B can come to your rescue here:
    #!perl -l package A; sub foo { "A::foo" } sub bar { 'A::bar' } package C; @ISA = 'A'; sub bar { 'bar' } package main; use B 'svref_2object'; $x = bless {}, 'C'; for (qw(foo bar)) { print "$_ is from ", svref_2object(UNIVERSAL::can($x, $_))->GV->ST +ASH->NAME; }

      The stash name is the name of the current package in which perl compiled the method. It can be wrong in cases where a method in a class comes from elsewhere, such as a role or a mixin.

        No, this is all compiled in main:
        #!perl -l $y='main';$A::y='A';$C::y='C'; sub A::foo { $y } sub A::bar { $y } @C::ISA = 'A'; sub C::bar { $y } use B 'svref_2object'; $x = bless {}, 'C'; for (qw(foo bar)) { print "$_ -> ", $x->$_, " from ", svref_2object(UNIVERSAL::can($x, + $_))->GV->STASH->NAME; }
        I guess the role and mixin stuff on CPAN must do something else if it breaks this.
Re: Detecting which class a method is defined in
by pajout (Curate) on Apr 03, 2011 at 11:41 UTC
    Try to put this into your class A:
    use Class::ISA; sub method_class { my ($self, $method_name) = @_; my $coderef; my $class; foreach (Class::ISA::self_and_super_path(ref($self)||$self)) { my $coderef_cur = $_->can($method_name); last unless defined $coderef_cur; last if defined $coderef and $coderef ne $coderef_cur; $coderef = $coderef_cur; $class = $_; } return $class; }
    ...it is not very tested, and I am not sure about autoloading, but I suppose this is what you seek. BUT, remember Merlyn's words, class would never care about method actually launched. Update: I did not tested multiple inheritance.
      Shouldn't you use base instead of ISA, well at least according to Perl::Critic?
      Don't use '#ff0000':
      use Acme::AutoColor;
      my $redcolor = RED();
Re: Detecting which class a method is defined in
by yngwi (Initiate) on Apr 04, 2011 at 19:18 UTC
    Thanks for all your help!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://897088]
Front-paged by chrestomanci
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (3)
As of 2024-04-19 02:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found