# Inheritance and method resolution Method lookup in Perl is simple in the single-inheritance case and genuinely subtle once diamonds or mixed class systems enter the picture. This chapter covers the full story: the MRO algorithms, `SUPER::`, the [`isa`](../../p5/core/perlfunc/isa) operator, `can`, `DOES`, and the interaction between classical and modern classes in one hierarchy. ## The lookup algorithm When you write `$obj->foo(@args)`, Perl does the following: 1. Determine the class. For an object, it is the class the referent was blessed into; for a class-method call, it is the invocant itself. 2. Walk the class's **method resolution order** (MRO) in sequence. For each package in the order, look for a sub named `foo`. 3. The first match wins. If no match is found in any class on the MRO, walk again looking for `AUTOLOAD`. 4. If no `AUTOLOAD` is found either, throw `Can't locate object method "foo" via package "Class"`. The MRO is what the class's `@ISA` chain linearises to. The linearisation rule depends on which MRO is in effect. ## The two MROs: `dfs` and `c3` Perl ships two MRO algorithms: - **`dfs`** — depth-first search of `@ISA`. The default. Walk each parent, and each parent's parents, left-to-right, diving fully into each subtree before moving on. - **`c3`** — the C3 linearisation used by Python, Raku, and many others. Guarantees monotonicity: a subclass never appears later than one of its ancestors in the lookup order. For single inheritance the two are identical: the list walks straight up the chain. For multiple inheritance they diverge. Consider the diamond: ``` A / \ B C \ / D ``` - **`dfs`**: `D, B, A, C, A` (collapsed to `D, B, A, C`). A method on `C` that overrides `A` is **shadowed** by `A` because `A` is reached through `B` first. - **`c3`**: `D, B, C, A`. `C`'s override is visible. C3 is almost always what you want under multiple inheritance. Opt in per-class: ```perl use mro 'c3'; package Diamond::D; our @ISA = ('Diamond::B', 'Diamond::C'); ``` For classes declared with [`class`](../../p5/core/perlfunc/class), multiple inheritance is not supported at all, so the MRO choice is purely a linear walk and the default `dfs` is fine. ## `SUPER::` `$self->SUPER::foo(@args)` calls `foo` in one of the parent classes of *the package the current method was compiled in*. That last phrase is the one everyone gets wrong. ```perl package Animal; sub speak { 'some sound' } package Dog; our @ISA = ('Animal'); sub speak { 'woof' } package Puppy; our @ISA = ('Dog'); sub speak { my $self = shift; return $self->SUPER::speak; } ``` `Puppy::speak` calls `SUPER::speak`. Perl looks up from **`Puppy`** (the compilation package), not from `ref($self)`. The search starts in `Puppy`'s `@ISA`, so it finds `Dog::speak` and returns `'woof'`. This matters when methods are inherited and the child calls `SUPER::` from within. Because `SUPER::` is anchored to the compile-time package, a method inherited from `Dog` and invoked on a `Puppy` object will still call `Animal::` via its `SUPER::`, not `Dog`. Usually that is the right behaviour; when it is not, reach for explicit chain navigation with `next::method`, covered below. ## `next::method` — the MRO-aware SUPER `mro::next::method` (exposed as `$self->next::method(@args)`) walks the live MRO from the current method's *actual* call position, not from the compile-time package: ```perl use mro 'c3'; sub speak { my $self = shift; return $self->next::method; } ``` Under C3 with a diamond, `next::method` is what you want; `SUPER::` can skip a sibling branch because it only consults the left-most ancestor. ## The `isa` operator The [`isa`](../../p5/core/perlfunc/isa) operator tests class membership without the footgun of `UNIVERSAL::isa` called as a function: ```perl if ($obj isa 'File::MP3') { ... } if ($obj isa File::MP3) { ... } # bareword form ``` Both `bless`-based and [`class`](../../p5/core/perlfunc/class)-declared classes answer `isa` correctly, and subclass relationships flow through `:isa` and `@ISA` identically. Three rules worth remembering: - `isa` returns false (not an error) when given a non-object. `42 isa Foo` is false. `undef isa Foo` is false. - `isa` respects the live MRO at the moment of the call. If code pushes onto `@ISA` at runtime, `isa` sees it. (This is another reason pperl rejects `@ISA` manipulation for `class`-declared classes — the guarantees would become muddy.) - Prefer the [`isa`](../../p5/core/perlfunc/isa) operator over `UNIVERSAL::isa($obj, 'Class')`. The operator short-circuits on non-objects instead of croaking; the function-call form is also defeated by overloaded objects. ## `can` `$obj->can('method')` returns a code reference if the object has a method by that name, `undef` otherwise: ```perl if (my $code = $obj->can('save')) { $code->($obj, @args); } ``` Uses: - Feature-detection before calling: avoids the `Can't locate object method` error. - Dispatching to a method by name from a string held in a variable — more readable than the `$obj->$name` form when the method might not exist. Non-uses: - Do **not** use `can` to decide whether an object implements a conceptual role. A class can define a `save` method that does something completely unrelated to persistence. For role membership, see [roles and delegation](roles-and-delegation). ## `DOES` `$obj->DOES('RoleOrClass')` is the role-aware counterpart to `isa`. By default `DOES` delegates to `isa`, so for classes without explicit role machinery the two behave the same. Role systems (classical Moose, Moo, and the future core role feature) override `DOES` to also return true for roles the class consumes. ```perl if ($obj->DOES('Printable')) { ... } ``` In pperl, `DOES` is the right method to check when you want to ask "does this object implement the contract?" rather than "does this object inherit from this class?" ## Mixed classical / modern hierarchies `class`-declared and `bless`-based classes interoperate in both directions, subject to a handful of rules. ### A modern class inheriting from a classical class ```perl package Shape; # classical sub new { my ($class, %args) = @_; return bless { colour => $args{colour} // 'black' }, $class; } sub colour { $_[0]{colour} } use feature 'class'; class Circle :isa(Shape) { # modern inherits classical field $radius :param :reader; method area { 3.14159265 * $radius ** 2 } } ``` This works. The modern class's generated constructor delegates to the parent's `new`, and methods inherited from the classical parent appear on the modern child. The parent's hash-slot state lives *alongside* the child's field storage. Caveat: the modern child cannot reach into the parent's hash. `$self->{colour}` is not legal inside a method of `Circle`; you must call `$self->colour`. ### A classical class inheriting from a modern class ```perl use feature 'class'; class Animal { field $name :param :reader; method speak { 'some sound' } } package Dog; # classical inherits modern our @ISA = ('Animal'); sub new { my ($class, %args) = @_; return $class->SUPER::new(%args); } sub speak { 'woof' } ``` This also works — the modern parent's generated constructor is inherited, and `SUPER::new` resolves to it. The classical child must not try to mutate the parent's fields directly; fields are private to the class that declared them. ### What fails in mixed hierarchies - **Reaching `$self->{fieldname}` across the boundary.** Modern fields are not hash slots, and classical hash slots are not visible as fields. Always cross the boundary through a method. - **Multiple inheritance into a modern class.** The `:isa` attribute only takes one target. If you need to mix behaviour from multiple places, see [roles and delegation](roles-and-delegation). - **Runtime `@ISA` manipulation on a modern class.** Undefined behaviour. Treat `@ISA` as read-only for any class declared with [`class`](../../p5/core/perlfunc/class). ## Why multiple inheritance usually hurts Every language with multiple inheritance eventually discovers the same pathologies. Method lookup becomes order-dependent; diamond problems force you to think about linearisation; the "I inherited twice from the same root" case tangles initialisation. Roles — composition of behaviour without an inheritance relationship — solve the underlying sharing problem without the pathologies. In pperl the [`class`](../../p5/core/perlfunc/class) feature forbids multiple inheritance deliberately. Classical code that uses it should be migrating towards a role model; the [roles chapter](roles-and-delegation) is the next stop. ## Further reading - [`class`](../../p5/core/perlfunc/class) — full syntax of modern class declarations including `:isa`. - [`bless`](../../p5/core/perlfunc/bless) — the primitive under classical inheritance. - [`ref`](../../p5/core/perlfunc/ref) — reports a blessed reference's class name. - [`isa`](../../p5/core/perlfunc/isa) — the preferred class- membership operator. - [Roles and delegation](roles-and-delegation) — the composition- based alternative to multiple inheritance. - [Migration](migrating) — walking an existing hierarchy from classical to modern.