Tuesday, October 18, 2005

EuroOSCON 3 - Perl Best Practices (2) - prototypes

Like the true geek I am, this has kept me awake all night.

Damian Conway is dead against prototypes, and says they should all die a horrible death in a pit filled with spikes.
And snakes (I forgot about the snakes).

Prototypes on $@% are rubbish – I agree, but \$\@\% have some advantages.

Take the swap_arrays code in his book (p.196), let's think of some simple user mistookes:

Without prototypes:

swap_arrays(@sheep, @goats); # Missed out the \

Without prototypes, provided you are using strict, you get:

Can't use string ("Blackface") as an ARRAY ref while "strict refs" in use at …

("Blackface" is a sheep, we know about these things where I do live)

BUT the error is given as being in the subroutine, not at the call (where the actual error is). perl also stops right there, it does not detect that the next argument is wrong as well – we need to do another run to find that.

Mostly if we supply the wrong type, use strict 'refs' will save our bacon (or mutton). BUT:

swap_arrays([qw(one two)], [qw(three four)]);

does not give us an error, surprisingly. OK, at the end of the day we should not be calling a subroutine we do not understand, but if a user can, she will. If she thinks that the two lists are flattened (Damian's assumption with prototypes), then she clearly does not understand the thing anyhow.

With prototypes:

swap_arrays(\@sheep, \@goats); # Added a \

With a prototype we get an error for each argument at fault:

Type of arg 1 to main::swap_arrays must be array (not reference constructor)

Type of arg 2 to main::swap_arrays must be array (not reference constructor)

Execution of C:\proto.pl aborted due to compilation errors.

This time the error is reported correctly.

Also, with:

swap_arrays([qw(one two)], [qw(three four)]);

and a prototype we get a similar error message, again identified with the correct line number.

And another thing

And I nearly forgot, empty prototypes are the only way I know (other than hand-coding) of preventing any arguments being passed, as in:

sub void_sub () { ,,, }

Calling this subroutine would give an error at the point of the erroneous call.

The Volcano beats Joe

Let's face it though, Damian is right. If you want a standard there cannot be exceptions. The problem with prototypes is that everyone thinks they are like C/C++ prototypes, but most people don't even understand THEM. Take:

size_t myfunc (char string[4]);


int another ();

Neither do what most people think they do, and are misleading. So how do you expect to understand Perl prototypes on the same (false) basis? KISS.

No comments: