Reputation: 5317
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
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
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.
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