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

I wanted to check to see if the method I was writing was overriding an existing method in a parent class. That's when I realized that I don't know a truly clean way of doing that. I tried this, but it fails (as it should):

#!/usr/bin/perl -l use strict; use warnings; { package A; sub foo { 'Whee!' } sub check { return shift->SUPER::can('foo') } } print A->check->();

The only thing I can cleanly think of is walking through @ISA, but this seems like such an obvious thing that someone would have solved this.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: Detecting Overridden Methods
by ikegami (Patriarch) on Feb 05, 2007 at 16:24 UTC
    package PkgA; use List::Util qw( first ); BEGIN { our @ISA = qw( ... ); } sub foo { 'Whee!' } sub check { return first { $_->can('foo') } @ISA; }

      The code in the parent post is neither inheritable nor importable. Fix:

      use List::Util qw( first ); sub check { my ($self, $method) = @_; my $class = ref($self) || $self; my $isa = do { no strict 'refs'; \@{$class.'::ISA'} }; return first { $_->can($method) } @$isa; }
        Doesn't use List::Util qw( first ); generate an unwanted first() "method" (actually, a function) that is inherited to all children? I would have coded this as use List::Util (); and return List::Util::first { $_->can($method) } @$isa;.
Re: Detecting Overridden Methods
by diotalevi (Canon) on Feb 05, 2007 at 16:28 UTC

    I'd be looking at SUPER's find_parent and find_all_parents methods. Looks like just what you want.

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: Detecting Overridden Methods
by Rhandom (Curate) on Feb 05, 2007 at 18:43 UTC
    perl -e 'package B; sub foo {}; sub bar {}; package A; @A::ISA="B"; sub bar {}; sub baz {}; for (qw(foo bar baz)) { print "$_: " .(A->can($_) == B->can($_) ? " same" : " overwritten") ."\n"}'

    Prints
    foo: same bar: overwritten baz: overwritten


    Not sure if that is what you are looking for.

    my @a=qw(random brilliant braindead); print $a[rand(@a)];
      Ah - I see. You don't want to hard code the classes. My Bad. Then yes - you'll have to look at @A::ISA - but only @A::ISA.

      for my $i (@A::ISA) { for (qw(foo bar baz)) { print "$_: " .(A->can($_) == $i->can($_) ? " same" : " overwritten") ."\n"; } }


      my @a=qw(random brilliant braindead); print $a[rand(@a)];
Re: Detecting Overridden Methods
by sfink (Deacon) on Feb 05, 2007 at 19:31 UTC
    If you know the set of methods you'll need to query, you could check before any of your methods are installed.
    package MyPackage; use base "Whatever"; our $can_foo; BEGIN { $can_foo = 1 if MyPackage->can("foo"); } sub foo { 'Whee!' } sub check { return $can_foo; }
    Update: But in direct answer to your question, this (surprisingly) seems to work:
    MyPackage->can("SUPER::foo")

      our $can_foo;
      is not as good as
      my $can_foo;
      There's no need for a package variable here.

      MyPackage->can("foo");
      is not as good as
      __PACKAGE__->can("foo");
      Less redundancy means smaller chance to make an error.

      I had written this solution before coming up with the one I posted. I couldn't see any advantages to it, so I only included it in my post in comment tags.