views:

74

answers:

2

Suppose I have two objects $obj1 and $obj2 that are both instances of Moose classes. I want to find out which of the following applies:

  • $obj1's class is the same as $obj2's;
  • $obj1's class is a subclass of $obj2's;
  • $obj1's class is a superclass of $obj2's;
  • Neither object's class is a subclass of the other's.

How can I do this?

+8  A: 
  1. Is $obj1's class the same as $obj2's?

    ref $obj1 eq ref $obj2;
    
  2. Is $obj1's class a subclass of $obj2's?

    $obj1->isa(ref $obj2);
    
  3. Is $obj1's class a superclass of $obj2's?

    $obj2->isa(ref $obj1);
    
  4. Neither object's class is a subclass of the other's.

    See above.

Update:

In response to comments regarding roles applied at run time:

package My::X;

use Moose; use namespace::autoclean;

sub boo { }

__PACKAGE__->meta->make_immutable;

package My::Y;

use Moose; use namespace::autoclean;

extends 'My::X';

__PACKAGE__->meta->make_immutable;

package My::Z;

use Moose::Role; use namespace::autoclean;

requires 'boo';

package main;

use Test::More tests => 2;

use Moose::Util qw( apply_all_roles );

my $x = My::X->new;
my $y = My::Y->new;

ok($y->isa(ref $x), 'Before role was applied at runtime');

apply_all_roles($x, 'My::Z');

ok($y->isa(ref $x), 'After role was applied at runtime');

Output:

1..2
ok 1 - Before role was applied at runtime
not ok 2 - After role was applied at runtime
#   Failed test 'After role was applied at runtime' at C:\Temp\t.pl line 36.
# Looks like you failed 1 test of 2.
Sinan Ünür
In Moose, can you add roles or traits to individual objects? It's one of the areas where this thinking goes wrong if you're looking for equivalent behavior.
brian d foy
Actually, I'm planning to use this logic to make $obj1 and $obj2 mergeable, even in certain cases where one is a subclass of the other. So I need to decide which class's merge code to use. (That is, if I call `$obj1->merge_with($obj2)`, the call will be reversed to `$obj2->merge_with($obj1)` if necessary.)
Ryan Thompson
@brian you can, but it doesn't cause these snippets to give wrong answers, at least in a pure Liskov substitutability sense (example: if Subclass inherits from Base, $a is an instance of Base+Role (applied to $a at runtime), and $b is an instance of Subclass, it will say $b's class isn't a subclass of $a's class -- but in a very useful sense that's true.)
hobbs
@hobbs: are you sure? I think the `->isa` test will pass, even if the base class has roles that the subclass does not (which would violate Liskov).
Ether
@Ether to clarify: http://gist.github.com/628748
hobbs
+4  A: 

Using the Class::MOP underpinnings in Moose you can introspect all this information.

For eg:

{
    package Daddy;
    use Moose;
}

{
    package Kid;
    use Moose;
    extends 'Daddy';
}

my $son      = Kid->new;
my $daughter = Kid->new;

my $sons_class                  = ($son->meta->class_precedence_list)[0];
my $daughters_class             = ($daughter->meta->class_precedence_list)[0];

my @sons_subclasses             = $son->meta->subclasses;     # or better...
my @daughters_subclasses        = $daughter->meta->direct_subclasses;

my @sons_superclasses           = $son->meta->superclasses;

my @Daddies_children            = Daddy->meta->direct_subclasses;

Also see this SO question/answer How can I find all the packages that inherit from a package in Perl?

/I3az/

draegtun
If your using Moose, asking Moose for the answer is probably the right way to go. :)
brian d foy