Indirect Method Calls Must die();

In this blog post I'll talk about the problems that I have with Perl's indirect method call syntax, both stylistically and pragmatically, and what you can do to prohibit its use.

Pop Quiz, Hotshot

What does the following Perl code do?
save $myobject;
Is it:
  • A function call to the save function, passing $myobject as the argument, i.e. the same as
    save($myobject)
  • An indirect method call, calling the save method on $myobject, i.e. the same as
    $myobject->save()
The answer is complicated. It depends entirely if a function called save is in scope (either declared above or imported from another module with a use statement) when Perl is compiling the code, in which case it'll be the former rather than the latter. Does anyone else find this confusing? I know I sure do.

Just say no

At work we have a simple rule: You're not allowed to write code that uses indirect method calls. If you want to make a method call, our house coding style demands you write it explicitly using the normal direct method call. That way if you see the above code you know that it's a function call. The problem is that it's still entirely possible to use the indirect method call completely accidentally when you intended it to be a function call. Imagine that you've written the code and forgotten to use ObjectSaver qw(save); at the top of your module and import the save() function. Perl will blindly go ahead an compile your code as an indirect method call on $myobject! The real issue with this is that this won't result in an error straight away - the problem will only come to light when the code is actually executed and the non-existent save() method is called (or worse, $myobject really might have a save() method that you didn't mean to call..) If the code you're writing is one of those hard-to-reach and therefore hard-to-test codepaths (e.g. obscure error handling) there's a chance you could ship broken code to live without noticing it.

A Solution: The no indirect pragma

The solution is to use the indirect pragma from the CPAN. This pragma allows you to get perl to throw an exception whenever it encounters something it would normally compile into an indirect method call straight away. Getting it to do its thing is simple:
no indirect ':fatal';
And that's it. Now:
bash$ perl
use strict;
use warnings;
no indirect ':fatal';

my $myobject = bless {}, "SomeClass";
save $myobject;
Indirect call of method "save" on object "$myobject" at - line 6.
bash$
Hooray!

- to blog -

blog built using the cayman-theme by Jason Long. LICENSE