in reply to Finding the interface implemented by an object

You can use Class::MOP or it's offspring Moose to do this.

First the Class::MOP version ...

package TestPackage; use metaclass; # this sets up your class to use Class::MOP use Data::Dump qw( dump ); my $obj = bless {}, __PACKAGE__; print 'Can dump()' if $obj->meta->has_method('dump');
This will not print "Can dump()" since Class::MOP knows that the method is not actually from your package, but has been imported from another package. To find the "interface" with Class::MOP, you have a few choices. First you can get all the locally defined methods* like this:
my @methods = $obj->meta->get_method_list;
This will return a list of method names suitable for doing things like $obj->meta->has_method($method_name) and $obj->meta->get_method($method_name) and other such introspection and reflection. Or, your second choice is to get all the methods this $obj supports, including inherited methods. In this case you do the following:
my @methods = $obj->meta->compute_all_applicable_methods;
The items in @methods this time are slightly different, you get a HASH reference which contains the method name (in the name key), the name of the class in which the method lives (in the class key) and a CODE reference for the actual method (in the code key).

Now, you could also use Moose and Moose::Role to do similar things. Moose is basically syntactic sugar over the mechanisms that Class::MOP provides, so all the above examples apply here as well. With roles** and Moose::Role you can do the interface checking you are talking about. Here is an example:

package MyFooInterface; use Moose::Role; requires 'bar';
Then you apply the role to your class, which checks the role "interface" at compile time.
package MyFoo; use Moose; with 'MyFooInterface'; sub bar { ... } # the bar method is required, the # class will fail to compile if it is # not present
And you can also do your checking at runtime ...
my $foo = MyFoo->new; if ($foo->does('MyFooInterface')) { ... }
For more information, see the CPAN pages for Moose or Class::MOP, or for a quicker overview you can check out one of these talks recently given on the subject: And lastly, you can check out the two part article on Moose written by our very own merlyn.

Footnotes:
* Locally defined methods are those defined directly in your class, and not inherited.
** If you don't already know, a role is not unlike a mixin or the traits mentioned above, but with a little bit more of a Perl-ish twist. They are a core part of Perl 6 in fact.

-stvn

Replies are listed 'Best First'.
Re^2: Finding the interface implemented by an object
by j1n3l0 (Friar) on Nov 28, 2007 at 14:01 UTC
    On the subject of Moose, I have a question ... Is multiple inheritance possible using Moose?

    I have tried some simple examples such as this:

    package Animal; use Moose; sub speak { my $self = shift; print 'A ', ref $self, ' goes ', $self->sound() . "\n"; } 1; package Danger; use Moose; sub speak { my $self = shift; print 'through an eye patch ...' . "\n"; } 1; package Mouse; use Moose; extends qw(Animal Danger); has 'sound' => (is => 'rw', default => 'squeek'); after 'speak' => sub { my $self = shift; print '[but you can barely hear it!]' . "\n"; }; 1; package main; my $danger_mouse = Mouse->new(); $danger_mouse->speak(); 1;

    The output I get is:

    A Mouse goes squeek [but you can barely hear it!]

    If I used Class::Std to implement this (using CUMULATIVE(BASE FIRST)) like so:

    package Animal; use Class::Std; { sub speak : CUMULATIVE(BASE FIRST) { my $self = shift; print 'A ', ref $self, ' goes ', $self->get_sound() . "\n"; } } 1; package Danger; use Class::Std; { sub speak : CUMULATIVE(BASE FIRST) { my $self = shift; print 'through an eye patch ...' . "\n"; } } 1; package Mouse; use Class::Std; use base qw(Animal Danger); { my %sound : ATTR( :name<sound>, :default<squeek> ); sub speak : CUMULATIVE(BASE FIRST) { my $self = shift; print '[but you can barely hear it!]' . "\n"; } } 1;

    I get the output I expect:

    A Mouse goes squeek through an eye patch ... [but you can barely hear it!]

    Is there a way to achieve similar results with Moose? I would just like to know.

    Thanks in advance =)

    UPDATE

    I knew I should have finished reading that post first =(

    This is achievable with Moose::Roles ... and a little thought. Like so:

    package Animal; use Moose; sub speak { my $self = shift; print 'A ', ref $self, ' goes ', $self->sound() . "\n"; } 1; package Danger; use Moose::Role; requires 'speak'; after 'speak' => sub { my $self = shift; print 'through an eye patch ...' . "\n"; }; 1; package Mouse; use Moose; extends 'Animal'; with 'Danger'; has 'sound' => (is => 'rw', default => 'squeek'); after 'speak' => sub { my $self = shift; print '[but you can barely hear it!]' . "\n"; }; 1; package main; my $danger_mouse = Mouse->new(); $danger_mouse->speak(); 1;

    This gives the same output as the Class::Std version. My apologies all for jumping the gun.


    Smoothie, smoothie, hundre prosent naturlig!

      There are two important things to note about the Moose solution, which make it superior to the Class::Std solution.

      1. A Mouse is not a Danger
      2. Inheritance is an "is-a" relationship, and the Class::Std version incorrectly models the Mouse's relationship with Danger. The Moose version states that a Mouse "does" Danger, which still doesn't read quite right, but Danger is clearly more of a Trait of this particular Mouse, and not something that the Mouse "is".

      3. The CUMULATIVE(BASE FIRST) approach lacks a degree of control
      4. Because CUMULATIVE(BASE FIRST) determines the order in which your methods are called, you are limited to how much control you can have. Using the Moose modifiers before/after/around you have a great degree of control over when and how your methods get called. Moose also provides augment/inner which only works with classes (it makes no sense for roles), but also provides a more flexible and powerful means of controlling dispatch. See the Moose::Cookbook::Recipe7 for a good example of this.

      It should also be noted (with all due respect to TheDamian) that that Class::Std has 56 outstanding Bugs some over 2 years old and many which are quite serious. It also seems to be no longer maintained (last upload was Feb. 2006). In contrast, Moose is very actively developed by a handful of developers and is being used heavily in several large production sites so bugs tend to get fixed rather quickly.

      -stvn