Reputation: 1983
Is there a way for me to return from my caller instead of to my caller? e.g.
sub foo {
bar();
# this never gets executed
}
sub bar {
return_from_caller(5);
}
# This prints 5
print foo();
(Rationale: I am writing a function memoize_self that memoizes a function from within the function itself. I'd like it to work like this:
sub complex_function {
my ($x, $y) = @_;
memoize_self({key => $y, expires_in => '5min'));
# compute $result
return $result;
}
memoize_self will check its cache, and if it gets a hit, return the cached value from its caller. Otherwise, it will re-call the function (with a dynamically scoped var to avoid the obvious infinite loop), store the return value in the cache and again return it.
Without the ability to return from caller, I'd probably use $_ and write it this way:
return $_ if memoize_self({key => $y, expires_in => '5min'));
But this is extra noise, and also doesn't take context into account.)
EDIT: To the people who reasonably suggested Memoize - yes, I should have said, I know this module well. I'm writing a more modern and featureful version of Memoize based on CHI.
But as relates to this question, there are cases where it's useful to memoize from within the function rather than outside the function (Memoize only does the latter). It makes it easy to customize the cache key and/or determine whether you want to memoize at all for this particular call. e.g.
sub complex_function {
my $key = ...; # normalize arguments
if (...) { # is it worth memoizing in this case?
memoize_self({key => $key});
}
}
I also like the way it is wrapped up in the function instead of creating its own line outside, ala state variables.
Upvotes: 2
Views: 296
Reputation: 8352
Take a look to CPAN module Memoize - Make functions faster by trading space for time, this will probably solve your problem.
Upvotes: 1
Reputation: 442
Another solution is to use the Want module's double_return method, which makes your next return pop off two call frames:
#!/usr/bin/env perl
use warnings;
use strict;
use Want;
sub foo {
Want::double_return;
return 11;
}
sub bar {
foo();
# never executed
return 55;
}
# prints 11;
print bar();
Upvotes: 0
Reputation: 3601
"Is there a way for me to return from my caller instead of to my caller?"
Yes, there are several.
goto
to jump back. See perldoc -f goto
.eval
and die
for a more control jump. See perldoc -f eval
and perldoc -f die
.goto
it. When you do this, it will return to the sub with the goto
caller. See perldoc -f goto
.Of course, most people would tell you to rewrite everything to avoid gotos and make life easier for those maintaining your code but what have they ever done for you?
Upvotes: 0
Reputation: 5678
Continuation::Escape does exactly what you want. Memoize is what you really need, however, as Nikhil pointed out.
Upvotes: 7