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

Dear monks,
I wrote a recursive program but as it turned out, the program will potentially be using quite a lot of data. Thus the tendancy to go too deep in recursion loop and run out of memory.
So, I used the simple work around of using goto &func_name; It worked quite well until I ran an actual load test. The program ran out of memory.
After some tests, I managed to pin point the error to following. In the process I found a work around to the problem. But I can't figure out what's happening here. It looks like a memory leak in Perl to me.

Program that crashes:
=====================
use strict; test1(); sub test1 { my $v=0; if ($v = get_true()) { goto &test1; } } sub get_true { return 1; }


Program that does NOT crash:
=====================
use strict; test1(); sub test1 { my $v=0; $v = get_true(); if ($v) { goto &test1; } } sub get_true { return 1; }

The proglem lies in the 'if' with assigment statement. As I have solved the problem, it's not urgent. But I am very much interested to know what's going on here.
Thanks,
Thushan

Replies are listed 'Best First'.
Re: Recurse using goto; Bug?
by Joost (Canon) on Jul 18, 2008 at 21:05 UTC
Re: Recurse using goto; Bug?
by TGI (Parson) on Jul 18, 2008 at 22:03 UTC

    Why use the goto at all? A do while loop does the same thing nicely.

    use strict; use warnings; test1(); sub test1 { while () { my $v = 0; next if $v = get_true(); } } sub get_true { 1 }

    My question comes as a result of a lifetime of being told to avoid goto--it's considered harmful, after all.

    I've seen this pattern of recursion via goto() show up here a few times and I am interested in the pros and cons of this technique.

    Now, I can see the harm in abusing goto, but IMO the original code hardly counts as abuse. How does the OP's code behave differently than my while loop? Are there any significant differences that would make the decision to use one approach or the other anything but stylistic choice?


    TGI says moo

      goto &function is completely different than the type of goto that you've been told to avoid (see the docs). Using tail-recursion is a common and efficient technique in some other languages. Using goto for tail-recursion in perl is (supposed to be) efficient memory-wise (though the OP has proven otherwise), but not at all efficient speed-wise, so the while loop (or some other normal iteration) as you suggest would generally be preferred (if speed is at all an issue).
Re: Recurse using goto; Bug?
by wade (Pilgrim) on Jul 18, 2008 at 21:14 UTC

    That's interesting. In neither place do I find a terminating condition for the recursion so, theoretically, they both should run forever.

    I have a separate question -- if you're going to use tail-recursion, anyway, why don't you just use iteration? If I understand things, correctly, you can only do tail-recursion with the 'goto &label' method.

    Update: I added some clarification.

    --
    Wade

      The issue wasn't whether it will run forever or not, but whether it would run out of memory or not. The OP is of the opinion that the memory usage of both snippets should be constant, while it's only the case for the second snippet.

        You're absolutely right, of course. The two should be identical. As it is, one of the snippets is silly and the other is silly and sucks up all memory. I sit, corrected. 8o).

        --
        Wade
Re: Recurse using goto; Bug?
by Thushan2 (Initiate) on Jul 19, 2008 at 18:57 UTC
    Thank you for all the replies.
    (Btw, I am the same Thushan. I don't have access to my other profile as I created it yesterday using my office email.)

    Apologies for if I was not clear enough in my original post. But most people clearly saw the problem.

    But obviously some did not see the problem.

    It's clear that the above snipet is not some production code. It was written to show the bug. So, don't look at the wrong place and call it silly code. :)

    For those who want to test:
    First run the second code snipet and observe your system memory. You'll see no increased usage in it. Then run the first code snipet and do the same observation. You'll see that memory usage gradually increases over time (for the Perl process). That should not be the case. Read goto &sub_name syntax documentation.
    I'll report a bug for this as suggested by Joost.
    Thank you