(aka known as which language am I using again?)
Dave Rolsky has a new post on perl 5 overloading. It’s fairly informative, but it contains this little gem (emphasis mine):
Defensive programming, for the purposes of this entry, can be defined as "checking sub/method arguments for sanity".
Blanket statements like this really get my gripe up. Let’s have a look at defensive argument checking in Perl taken to its illogical conclusion.
Defensive Primitive Type Checking
use strict; use warnings; use Carp; use Scalar::Util 'looks_like_number'; sub can_legally_drink { my $age = shift; croak "$age is not a number" unless looks_like_number($age); return $age >= 18; } print can_legally_drink('x'), "\n";
And fantastic news! can_legally_drink correctly detected that my argument isn’t a number.
x is not a number at age.pl line 10
main::can_legally_drink('x') called at age.pl line 14
But hang on a minute. Not all integers are ages. Surely we want to check if a real age type was passed in.
Checking For A ‘Real’ Type
My stripped down defensive age type might look something like this.
package age; use Carp; use Scalar::Util 'looks_like_number'; sub isa_age { my $arg = shift; return ref($arg) and blessed $arg and $arg->isa('age'); } sub new { my ($class, $years) = @_; croak "$years is not a number" unless looks_like_number($years); bless { years => $years }, $class; } sub years { return $_[0]->{'years'} } sub less_than { my ($self, $other) = @_; croak "$other is not an age" unless isa_age($other); return $self->years() < $other->years(); }
And then my calling code can look like this:
package main; sub can_legally_drink { my $age = shift; croak "$age is not an age" unless $age->isa('age'); return ! $age->less_than(age->new(18)); } print can_legally_drink(age->new(18)), "\n"; print can_legally_drink(18), "\n";
And woohoo, the second line throws an error as I wanted.
Actually, I don’t write Perl like this. Dave, you probably want to avoid working on code with me, thanks.
Moose
To be fair, Rolsky is talking his own book. Moose has a bunch of stuff that handles all this type checking malarky nice and cleanly. If you’re building something big in Perl, you should take a look.
But if you really care about types, I mean defensive programming that much, you could use a statically typed language instead and then you even get fast code thrown in for free.