Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re: Are prototypes evil?

by talexb (Chancellor)
on Sep 03, 2002 at 12:50 UTC ( [id://194745]=note: print w/replies, xml ) Need Help??


in reply to Are prototypes evil?

Wow. I had heard of prototypes in Perl (and think they are indispensable in C programming), but hadn't read up on them. ++ to Aristotle for his clear explanation (as well as others). Was there an RFC for the prototype feature in Perl that explains why it was implemented differently than C's prototypes?

In case there are non-C programmers out there, let me explain about C prototypes and why they're fantastic. For example, the string compare function strcmp has the following prototype:

    int strcmp ( const char *s1, const char *s2 );
This means that you gotta call strcmp with two char * variables, and the variable you store the result in has gotta be an int. Use anything else, and the compiler will issue a warning.

The difference already explained in numerous replies is that instead of complaining that there is a mis-match between the prototype and the call, Perl just 'fixes' the call. I wonder if there should be a use that enables a warning when Perl has 'fixed' something. Then again, that might only happen at run-time. Interesting question.

--t. alex
but my friends call me T.

Replies are listed 'Best First'.
Re: Re: Are prototypes evil?
by demerphq (Chancellor) on Sep 03, 2002 at 18:13 UTC
    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.

    Cheers,

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

Re^2: Are prototypes evil?
by Aristotle (Chancellor) on Sep 03, 2002 at 13:37 UTC
    Then again, that might only happen at run-time.

    That's not a "might", it's bullseye.

    The compiler cannot know what's going to happen. You might think it will; if you see foo(@bar) and the prototype is ($), it's obviously a violation, right? But what happens when I have foo(bar())? In fact, the function might return a single return value some of the time and multiple ones at other times. There's no way for the compiler to know. It can only be determined at runtime. Prototypes as they're known from statically, strongly typed languages are not possible in Perl due to the very nature of the language.

    Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://194745]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (2)
As of 2024-04-26 00:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found