Hi! Please consider following me on twitter: @hanekomu.

Error::Return

I've released Error-Return. It exports one function, RETURN, to be used within a try-block (see Error). It is a more intuitive way of returning from the subroutine that contains the try-block.

try() takes a coderef using the & prototype so it looks more like a normal Perl block or like map() or grep(). But the "block" is still just an anonymous subroutine, so using return within the sub won't do what you think it will do. For example:

use Error ':try';

sub doit {
    print " in doit, before try\n";
    try {
        print "  in try: start\n";
        return 456;
        print "  in try: end\n";
    } catch Error with {
        my $E = shift;
        print "  caught error [$E]\n";
    };
    print " in doit, after try\n";
}

print "before doit\n";
my $x = doit();
print "doit() returned [$x]\n";
print "after doit\n";

The return in the try-block (we call it a block, but it really isn't) looks like it should return from doit(), but it doesn't - it just returns from the anonymous sub that was passed to try(). Therefore, this program prints the following:

before doit
 in doit, before try
  in try: start
 in doit, after try
doit() returned [1]
after doit

So in doit, after try is still reached, and doit() returns 1 because of its last print statement.

While that is the correct behaviour, it is unintuitive. This module provides a more powerful way of returning.

Error::Return exports one function, RETURN, which is like return except that it doesn't just return to its upper scope but smashes right through it to the next-higher scope. Actually, it skips two scopes, because it has to return from the try() subroutine as well. It does take care of the cleanup that try() would normally perform.

So now you can say:

use Error ':try';
use Error::Return;

sub doit {
    print " in doit, before try\n";
    try {
        print "  in try: start\n";
        RETURN 456;
        print "  in try: end\n";
    } catch Error with {
        my $E = shift;
        print "  caught error [$E]\n";
    };
    print " in doit, after try\n";
}

print "before doit\n";
my $x = doit();
print "doit() returned [$x]\n";
print "after doit\n";

and it prints

before doit
 in doit, before try
  in try: start
doit() returned [456]
after doit

which is more intuitive.

Write a comment | Bookmark and Share

posted at: 16:46 | path: /dev | permalink | 0 comments | 0 trackbacks

Comments are closed for this story.

Trackbacks are closed for this story.