http://www.perlmonks.org?node_id=130071

apprentice has asked for the wisdom of the Perl Monks concerning the following question:

I have one function that calls itself recursively. When I prototype that function, I get the error message: "parseLine() called too early to check prototype at ssi-parser.pl line 381".
Here's the code:
#!/usr/local/bin/perl -w use strict; sub main() { doSomething("1","2","0"); print "Done\n"; } sub doSomething($$$) { my ($data1, $data2, $count) = @_; print "\$data1: $data1, \$data2: $data2, \$count: $count\n"; $data1++, $data2++, $count++; if ($count < 4) { doSomething($data1, $data2, $count); } } main();
Anyone know how to get prototyping to work for this?

Thanks,
Apprentice

Replies are listed 'Best First'.
Re: problem prototyping a self-recursing function
by japhy (Canon) on Dec 07, 2001 at 01:13 UTC
    The bigger problem is you're calling the function before you define it, so that call doesn't use the prototype either. Just declare your function ahead of time:
    sub foo ($$$); # your code sub foo ($$$) { # ... foo(...) if ...; # ... }

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

      Exactly, buy definition prototyping is predaclaring functions and the allowable arguements for that function.

      What you were doing is only defining them and the args at the point you use them, that's only half the picture. Predefining them allows the complier (in this case the interpreter) to make certain assumptions about the calls to the function and error out if they are wrong.

      One other point that should be made is that there are reasons NOT to prototype in Perl. Do a search on this site and you will come up with several nodes that debate that very point.

      "Nothing is sure but death and taxes" I say combine the two and its death to all taxes!
Re (tilly) 1: problem prototyping a self-recursing function
by tilly (Archbishop) on Dec 07, 2001 at 04:35 UTC
    IMHO the biggest problem is that you believe that prototypes do something useful for you in Perl. They do not. Stop using prototypes and that problem, along with others, goes away.
Re: problem prototyping a self-recursing function
by frankus (Priest) on Dec 07, 2001 at 16:26 UTC
    You probably already know this, or perhaps don't need to hear it.
    Recursion makes for biig overheads, and without exception anything using recursion can be done with loops.

    Part of the reason that people use recursion is to map the solution precisely to the problem set,
    this is often due to not understanding the problem, although I'm not implying this is the case here.
    i.e Using your simple example.

    #!/usr/local/bin/perl -w use strict; sub main() { doSomething(1,2,0); print "Done\n"; } sub doSomething{ my ($data1, $data2, $count)=@_; for($count..3){ $data1++,$data2++,$count++; print "\$data1: $data1, \$data2: $data2, \$count: $cou +nt\n"; } } main()

    Now this is probably redundant information, or at worst seems like bigotry, but
    believe me, I've used recursion in LISP for years, but whilst I enjoyed it, it's not effecient.

    If you're just doing this as an exercise in recursion, that's fine, otherwise I'd advocate developing
    a loop alternative and benchmarking the two, the dividends should speak for themselves.

    --

    Brother Frankus.

    ¤

      here's a benchmark of the two:

      #!/usr/bin/perl -w use strict; use Benchmark; my $trials = 50000; timethese($trials, { 'recursive' => sub {doSomethingRec(2,2,0);}, 'loop' => sub {doSomethingLoop(2,2,0);} }); sub doSomethingRec { my ($data1, $data2, $count) = @_; print "\$data1: $data1, \$data2: $data2, \$count: $count\n"; $data1++, $data2++, $count++; if ($count < 4) { doSomethingRec($data1, $data2, $count); } } sub doSomethingLoop { my ($data1, $data2, $count)=@_; for($count..3){ $data1++,$data2++,$count++; print "\$data1: $data1, \$data2: $data2, \$count: $cou +nt\n"; } }

      the results on my system (1GHz P4 w/ 512MB) for $trials = 50000:

            loop:  3 wallclock secs ( 2.09 usr +  0.01 sys =  2.10 CPU) @ 23809.52/s (n=50000)
       recursive:  2 wallclock secs ( 2.19 usr +  0.01 sys =  2.20 CPU) @ 22727.27/s (n=50000)
      

      for $trials = 500000:

            loop: 21 wallclock secs (20.91 usr +  0.06 sys = 20.97 CPU) @ 23843.59/s (n=500000)
       recursive: 23 wallclock secs (21.89 usr +  0.09 sys = 21.98 CPU) @ 22747.95/s (n=500000)
      

      so i'd be inclined to say that there isn't really a very significant difference between the looped and recursive versions in this case (not surprising since the subroutine doesn't return anything and thus the perl interpreter ought to be able to optimize things fairly well).

      of course, things change a little if you increase the level of recursion. eg, changing it to $count < 40 in the recursive one and to $count..39 in the loop version (and $trials = 50000):

            loop: 17 wallclock secs (16.46 usr +  0.09 sys = 16.55 CPU) @ 3021.15/s (n=50000)
       recursive: 24 wallclock secs (23.48 usr +  0.12 sys = 23.60 CPU) @ 2118.64/s (n=50000)
      

      increase the level of recursion much more and you run into the real problem of doing recursion in perl. it limits the level of recursion so you start getting runtime errors if you go over something like 50 deep (i'm not sure exactly what the level is). IMO, this, not the efficiency reason, is why you may want to avoid heavy use of recursion in perl.

      the issue of loop vs recursion efficiency is highly dependent on the language used. it's been my experience with functional languages like ML that recursion is significantly more efficient than looping because the language is designed for it and the compiler/interpreter is optimized for recursion. i haven't done much LISP programming but i'm surprised that you had efficiency problems with recursion; i thought it was one of those recursion optimized languages.

      anders pearson

        I might have appeared zealous but I was not decrying recursion as being all bad; just advocating discretion in it's use.

        We had a LISP lecturer who made grown men blubber if their reursive functions were over 3 lines<br and used sarcasm if iterative solutions were suggested....
        /me shudders at the memory of his sarcasm

        --

        Brother Frankus.

        ¤