Samiron
Samiron

Reputation: 5317

perl goto&Name vs return

I came accross a piece of perl code recently. The code looks like below

package CODE;

sub _doJob
{
    $result = JOB->new(@_)->doIt();
    return $result;
}

sub _doFirstJob
{
    unshift @_, '1';
    goto &_doJob;
}

sub _doSecondJob
{
    unshift @_, '2';
    goto &_doJob;
}

sub _doThirdJob
{
    unshift @_, '3';
    goto &_doJob;
}

and then calling the functions like

$result = CODE::_doFirstJob($a);
$result = CODE::_doSecondJob($a);
$result = CODE::_doThirdJob($a);

Question is what is the significance of goto here? If I write similar function calls with return, like below, what would be the problem?

package CODE;

sub _doJob
{
    $result = JOB->new(@_)->doIt();
    return $result;
}

sub _doFirstJob
{
    unshift @_, '1';
    return &_doJob(@_);
}

sub _doSecondJob
{
    unshift @_, '2';
    return &_doJob(@_)
}

sub _doThirdJob
{
    unshift @_, '3';
    return &_doJob(@_)
}

I could still call these functions in same way

$result = CODE::_doFirstJob($a);
$result = CODE::_doSecondJob($a);
$result = CODE::_doThirdJob($a);

I know that goto &NAME actually makes perl to exit from current function and replace it with the new function in call stack. But how am I being benefited by this here?

Upvotes: 2

Views: 170

Answers (2)

rurban
rurban

Reputation: 4131

Unfortunately the tail call myth is only a myth. A goto still creates a new stack frame and is not faster than recursion. I experimented with eliminating this cost with cperl, doing real tail recursion, overwriting the stack values, but I don't think I've properly solved it yet. The whole ABI is highly deoptimized. And it would only work with cperl signatures as only those use the stack ABI as XS. With pure perl5 you are in the same mess as python.

Upvotes: 1

choroba
choroba

Reputation: 241978

You can save some time and memory by skipping the stack handling. You can use Benchmark to test if the difference is significant in your case.

Reading about "Tail Call" might also give some information. For example, see this old thread at PerlMonks.

Update

I tested with the following script:

sub rec {
    $_[0]++;

    sleep 5, return if $_[0] > 1000;

    return rec(@_); # Comment this line.
    goto &rec
}

rec(1 .. 200);

The time difference isn't measurable, the memory consumption is quite different: the return case takes almost twice as more bytes than the goto one. With higher number of iterations, the memory consumption stays the same for goto, but grows with return.

Upvotes: 1

Related Questions