8

In Perl5 and Moose, linear isa or linearized isa helps make sense of class hierarchies.

The method WHAT shows the concrete type of a value:

> 42.WHAT
(Int)

How do I show something like

> 42.hypothetical-type-hierarchy
(Int) ┬ is (Cool) ─ is (Any) ─ is (Mu)
      └ does (Real) ─ does (Numeric)

… possibly with further lines for each consumed role?


edit: example with two strands of roles

class Beta {}
role Delta {}
role Gamma does Delta {}
role Eta {}
role Zeta does Eta {}
role Epsilon does Zeta {}
class Alpha is Beta does Gamma does Epsilon {}

# (Alpha) ┬ is (Beta)
#         ├ does (Gamma) ─ does (Delta)
#         └ does (Epsilon) ─ does (Zeta) ─ does (Eta)

my $ai = Alpha.new
$ai.^mro        # ((Alpha) (Beta) (Any) (Mu))

$ai.^roles      # ((Epsilon) (Zeta) (Eta) (Gamma) (Delta))
                # flat list, not two-element list of a tuple and triple‽
daxim
  • 39,270
  • 4
  • 65
  • 132
  • 1
    `.WHAT` doesn't _show_ anything, it gives you the type object. Which for types that don't have any `::` in them `.gist` into something halfway sensible. You should really be calling `.^name`. – Brad Gilbert May 30 '17 at 15:20

1 Answers1

9

You can query the meta object with

> 42.^mro
((Int) (Cool) (Any) (Mu))

where mro stand for method resolution order and

> 42.^roles
((Real) (Numeric))

You can control which roles are returned via the adverbs :local (exlude roles inherited from parent classes - only available on classes) and :!transitive (exclude roles composed via another role - available on both roles and classes).


The following should get you started:

my $depth = 0;
for Alpha.^mro {
    say "is {.^name}";
    (sub {
        ++$depth;
        for @_ {
            say '  ' x $depth ~ "does {.^name}";
            &?ROUTINE(.^roles(:!transitive)); # recursive call of anon sub
        }
        --$depth;
    })(.^roles(:local, :!transitive));
}

Given your example code with slight modifications

role Delta {}
role Gamma does Delta {}
role Eta {}
role Zeta does Eta {}
role Epsilon does Zeta {}
class Beta does Gamma {}
class Alpha is Beta does Gamma does Epsilon {}

it produces the output

is Alpha
  does Epsilon
    does Zeta
      does Eta
  does Gamma
    does Delta
is Beta
  does Gamma
    does Delta
is Any
is Mu
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • Sorry, I don't understand the adverb part. Can you exemplify with the second example in my edited post? – daxim May 30 '17 at 08:42
  • 2
    @daxim An [adverb](https://docs.perl6.org/language/glossary#Adverb) is a named argument that modifies what a function does. For example, passing `:!transitive` drops out roles that are `does`d [transitively](http://www.dictionary.com/browse/transitively). (The `!` means "not", i.e. `:!transitive` is analogous to the English adverbial phrase "not transitively".) So `say $ai.^roles(:!transitive)` with your code displays just `((Epsilon) (Gamma))`. – raiph May 30 '17 at 10:44
  • 2
    This feels like a nice utility module in the ecosystem. *hint* *hint* :-) – Elizabeth Mattijsen May 31 '17 at 10:23