Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Re: Re: Are prototypes evil?

by demerphq (Chancellor)
on Sep 03, 2002 at 18:13 UTC ( #194837=note: print w/replies, xml ) Need Help??

in reply to Re: Are prototypes evil?
in thread Are prototypes evil?

If you read the FMTYEWTK article (there are links in this thread) by Tom C. then youll get a good idea of what prototypes are for, but heres a quickie explanation

Basically prototypes are a workaround for specifying input templates (they would be better called "function parameter context coercion templates" or something like it.) The idea is that perls tokenizer/lexer needs to handle a variety of ways that a function can be called, and which context its parameters should be in. For example take the scalar function. It puts its argument a scalar context, but it also needs to know that it accepts only a single item (ie have its argument _in_ a scalar context too). Otherwise the below code would print out "6" and not "5-Bar".

sub foo{ print join "-",@_}; my @array=qw(a b c d e); foo(scalar @array,"Bar");
Think about it, if we wrote scalar() by hand we might code it something like:
sub my_scalar { my $count=0; $count++ foreach @_; return $count; }
But of course then we couldnt say foo(my_scalar @array,"bar") as it would return the wrong value. We would have to write it as foo(my_scalar(@array),"bar") which im sure you admit would be a PIA considering the number of times and places you would have to do so. This kind of thing gets even more serious when you consider subs like push() which expect the @array as the first value. Without prototypes we would have to do push(\@somearray,@values) otherwise the array would become listified byt the subroutine call.

Templates also perform a limited kind of type validation, but, and heres the problem, not consistantly. And not in the way they think. For instance

sub listy(\@){ print join("*",@{$_[0]}),"\n"; } listy @array;
Ensures that the first object is indeed an array, but then silently converts it to a reference to the array and passes it on. It will of course perform a certain level of type validation as it will barf on a non array being in that spot, but this behaviour is inconsistent as a '$' prototype will _not_ complain when a non scalar is provided, but rather simply "scalarify" whatever is provided. (Whichever form of scalarification makes the most sense.)

So prototypes are a kludgy work around to some problems in parsing the fairly loose rules of perl, not a way to get your parameters checked at run time.

Do take the time to read Tom C's article. I have only made a minor attempt at explaining the issues here.

Incidentally there are some rare situations where prototypes come in useful. Examples may be found in some of Michael Schwern's modules for instance in Carp::Assert you will find

sub assert ($;$) { unless($_[0]) { require Carp; Carp::confess( _fail_msg($_[1]) ); } return undef; }
So why did he use prototypes here? Well he wanted people to be able to say
assert @array,"Array must have elements within";
instead of
assert scalar @array,"...";
This is what prototypes in perl are for, making the semantics of a subroutine perfom "naturally" in context. Unfortunately when people try to use them as parameter validation mechanisms the resulting subs tend to behave "unnaturally", as they stop behaving as functions would be expected to behave. And this is IMO evil.


Yves / DeMerphq
Software Engineering is Programming when you can't. -- E. W. Dijkstra (RIP)

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://194837]
[Corion]: ambrus: yeah, but the longer I think about it the more I come to the conclusion that you shouldn't try to mix threads and fork anyway :)

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (12)
As of 2017-10-19 14:57 GMT
Find Nodes?
    Voting Booth?
    My fridge is mostly full of:

    Results (254 votes). Check out past polls.