A moose

The override key­word in Perl’s Moose object sys­tem is a nice bit of code-​as-​documentation since it explic­it­ly states that a giv­en method over­rides from its super­class. It also has a super key­word that can be used inside an override, call­ing the next most appro­pri­ate super­class method with the same argu­ments as the orig­i­nal method.”

The Moose doc­u­men­ta­tion then goes on to say, The same thing can be accom­plished with a nor­mal method call and the SUPER:: pseudo-​package; it is real­ly your choice.” So when should you use one and not the oth­er? I decid­ed to find out.

First I defined a sim­ple Moose super­class with a sin­gle method:

package Local::MyClass;

use Moose;

sub my_method {
    return blessed $_[0];
}

__PACKAGE__->meta->make_immutable();

1;

And then a pair of sub­class­es, one using Moose’s override key­word and one with a plain sub:

package Local::MyClass::MyChildOverride;

use Moose;
extends 'Local::MyClass';

override my_method => sub {
    my $self = shift;
    return 'child ' . super;
};

__PACKAGE__->meta->make_immutable();

1;
package Local::MyClass::MyChildPlain;

use Moose;
extends 'Local::MyClass';

sub my_method {
    my $self = shift;
    return 'child ' . $self->SUPER::my_method();
}

__PACKAGE__->meta->make_immutable();

1;

So far so good, and both can be called successfully:

$ perl -Ilib -MLocal::MyClass::MyChildPlain \
  -MLocal::MyClass::MyChildOverride \
  -E '$PREFIX = "Local::MyClass::MyChild";
  for ( qw(Plain Override) ) {
    $object = "$PREFIX$_"->new();
    say $object->my_method()
  }'
child Local::MyClass::MyChildPlain
child Local::MyClass::MyChildOverride

Let’s toss in a new wrin­kle, though. What if we for­got to define the method in the superclass?

package Local::MyClassNoMethod;

use Moose;

__PACKAGE__->meta->make_immutable();

1;

Both ways of call­ing the super­class’s method will bug out, of course, but unlike a plain over­ride Moose will actu­al­ly pre­vent you from useing the offend­ing sub­class dur­ing the BEGIN phase:

$ perl -Ilib -MLocal::MyClassNoMethod::MyChildOverride \
  -E ''
You cannot override 'my_method' because it has no super method at /Users/mgardner/.plenv/versions/5.34.0/lib/perl5/site_perl/5.34.0/darwin-2level/Moose/Exporter.pm line 419
	Moose::override('my_method', 'CODE(0x7fe5cb811a88)') called at lib/Local/MyClassNoMethod/MyChildOverride.pm line 9
	require Local/MyClassNoMethod/MyChildOverride.pm at -e line 0
	main::BEGIN at lib/Local/MyClassNoMethod/MyChildOverride.pm line 0
	eval {...} at lib/Local/MyClassNoMethod/MyChildOverride.pm line 0
Compilation failed in require.
BEGIN failed--compilation aborted.

With plain method over­rid­ing, you only get an error if you try to call the super­class’s method. If your over­rid­den method does­n’t do that, it’s per­fect­ly safe to define and call. It’s only if you use that SUPER:: pseudo-​package that things blow up at runtime:

$ perl -Ilib -MLocal::MyClassNoMethod::MyChildPlain \
  -E '$obj = Local::MyClassNoMethod::MyChildPlain->new();
  $obj->my_method()'
Can't locate object method "my_method" via package "Local::MyClassNoMethod::MyChildPlain" at lib/Local/MyClassNoMethod/MyChildPlain.pm line 8.

Note that none of this is caught at com­pile time. perl -c will hap­pi­ly com­pile all these class­es and sub­class­es with­out a peep:

$ find . -name '*.pm' -exec perl -c {} \;
./lib/Local/MyClass/MyChildPlain.pm syntax OK
./lib/Local/MyClass/MyChildOverride.pm syntax OK
./lib/Local/MyClassNoMethod/MyChildPlain.pm syntax OK
./lib/Local/MyClassNoMethod/MyChildOverride.pm syntax OK
./lib/Local/MyClass.pm syntax OK
./lib/Local/MyClassNoMethod.pm syntax OK

So what can we con­clude? Moose’s override is a good way of describ­ing your intent with a sub­class, and it will catch you out if you try to use it with­out a cor­re­spond­ing method in a super­class. It is a non-​standard key­word though, so syntax-​highlighting edi­tors and code analy­sis tools won’t rec­og­nize it unless taught. Further, if your sub­class method does­n’t call the same method in a super­class you could even­tu­al­ly get away with remov­ing the lat­ter if you use a plain sub.

I’ve cre­at­ed a small GitHub project with the sam­ple code from this arti­cle, includ­ing test scripts.

What do you think? Is override suit­able for your Moose projects, or are you sat­is­fied with plain sub? Let me know in the comments.