2010/06/03

Why you should never use indirect object notation

On the subject of indirect object notation, kappa writes "Do not use it when it causes problems".

It always causes problems.
$ perl -MO=Deparse -e 'package Container;
sub new { shift->BUILD }
sub BUILD { my $contained = new Contained() }'
package Container;
sub new {
shift(@_)->BUILD;
}
sub BUILD {
my $contained = new(Contained());
}
-e syntax OK
What you meant, perhaps, was
$ perl -MO=Deparse -e 'package Container;
sub new { shift->BUILD }
sub BUILD { my $contained = Contained->new() }'
package Container;
sub new {
shift(@_)->BUILD;
}
sub BUILD {
my $contained = 'Contained'->new;
}
-e syntax OK
Basically, indirect notation breaks any time you're actually writing an object class. If you start indirectly invoking constructors (likely), you'll accidentally hit your own. Any time you go adding a new method to your own class - bang; you've just broken any indirect calls to that named method on any other object you'd be using. That sounds excessively fragile to me. Code that used to mean one thing suddenly means a different thing when you add seemingly-unrelated code in another place. Fragile breakage by action-at-a-distance. It even depends on the order of the source code:
$ perl -MO=Deparse -e 'package Container;
sub BUILD { my $contained = new Contained() }
sub new { shift->BUILD }'
package Container;
sub BUILD {
my $contained = 'Contained'->new;
}
sub new {
shift(@_)->BUILD;
}
-e syntax OK
And given probably most of the time you're writing code, you're writing objects, right? Even if the function you're writing currently isn't in an object class, it probably uses objects. Maybe one day you'll decide that function is useful in an object, so you'll copypaste that code elsewhere. This probably means most of your code ought not use indirect notation. If already most of it isn't using it, just get out of the habit NOW, before it is too late, and pretend that indirect notation does not exist at all. You'll save yourself a lot of pain later on.