NAME

Clean::Eval - Run code under eval without leaking $@ and get a rich error object back on failure.

DESCRIPTION

Perl's built-in eval is the standard way to trap exceptions, but it has two long-standing ergonomic problems:

Clean::Eval wraps eval in a way that avoids both problems. It localizes $@ so the caller's copy is never touched and always returns a blessed result object that is overloaded for boolean and string context. The object is true on success and false on failure regardless of what the wrapped code returned, so a single if check is enough to distinguish the two.

On success the block form also stashes the block's return value (taken in scalar context) in an out field on the object, so the typical pattern is:

if (my $ev = clean_eval { get_message() }) {
    $msg = $ev->out;
}
else {
    die $ev;        # stringifies to the trapped error
}

Both a block form (clean_eval { ... }) and a string form (clean_string_eval $code) are provided. The string form rewrites #line information so that any error reports the file and line of the caller, not an anonymous (eval N). The string form does not capture a return value - see "clean_string_eval".

SYNOPSIS

use Clean::Eval qw/clean_eval clean_string_eval last_error/;

# Block form - object is always returned; bool overload picks
# success vs failure; on success ->out holds the block's scalar
# return value.
my $msg;
if (my $ev = clean_eval { get_message() }) {
    $msg = $ev->out;
}
else {
    die $ev;        # stringifies to trapped error
}

# Or, branchless:
my $ev = clean_eval { risky() };
die "Failed: $ev\n  at $ev->{file} line $ev->{line}\n" unless $ev;
my $result = $ev->out;

# String form - same overloaded object, but no ->out is ever set
# (see "clean_string_eval" below). No need to add a trailing "; 1"
# - it is appended for you.
my $ev = clean_string_eval 'use SomeOptionalModule';
warn "Optional dep missing: $ev\n" unless $ev;

# Retrieve the most recent failure from anywhere
my $last = last_error();

EXPORTS

Nothing is exported by default. The three functions below may be imported individually using Importer-style syntax:

use Clean::Eval qw/clean_eval clean_string_eval last_error/;

RESULT OBJECT

Both clean_eval and clean_string_eval always return a blessed hashref of class Clean::Eval. It overloads boolean and stringification context:

The object is a plain hashref with the following keys. Which keys are present depends on whether the eval succeeded:

Convenience accessors ok, out, and error return the corresponding fields. to_string returns the same string the "" overload yields.

WHY NOT JUST USE eval?

You can, but you have to be careful. The idiomatic safe pattern looks like:

my $ok = eval { ...; 1 };
if (!$ok) {
    my $err = $@;
    ...
}

This is correct but verbose, and the ; 1 trailer is easy to forget. The $@ variable is also famously fragile: destructors that run during stack unwind can call eval themselves and reset it before you read it. Localizing $@ the way Clean::Eval does avoids that class of bug entirely.

PITFALLS

my $ev = clean_eval { ... } or die "$ev" does not work

This looks natural but contains a subtle bug. A lexical introduced by my is not in scope until the statement that declared it has finished, so the $ev referenced by die "$ev" is a different, package-global $ev (which is undef):

use Clean::Eval qw/clean_eval/;

# WRONG - $ev inside the die is the package global, not the lexical;
# the die fires (clean_eval returned a false-overloaded object) but
# with an empty message.
my $ev = clean_eval { die "foo" } or die "$ev";

Declare the lexical on its own statement first so it is in scope by the time the or die runs:

use Clean::Eval qw/clean_eval/;

# CORRECT - $ev refers to the lexical in both spots
my $ev;
$ev = clean_eval { die "foo" } or die "$ev";

Or split the check off into its own statement, which has the same effect:

use Clean::Eval qw/clean_eval/;

my $ev = clean_eval { die "foo" };
die "$ev" unless $ev;

The reliable rule: do not reference a my-declared variable in the same statement that declares it. Running with use warnings will diagnose this with "Name main::ev used only once: possible typo".

The block's return value is taken in scalar context

clean_eval stashes the block's return value in $ev->out, but it does so in scalar context. A block that returns a list will be collapsed to the last element (or to the list count, depending on the expression):

use Clean::Eval qw/clean_eval/;

my $ev = clean_eval { (1, 2, 3) };
# $ev->out is 3, not [1, 2, 3]

If you need a list result, write to an outer lexical from inside the block:

my @rows;
my $ev = clean_eval { @rows = fetch_rows() };
die $ev unless $ev;
# use @rows here

Scalar context is forced deliberately - the out field is a single scalar slot, and silently picking a list-handling convention would surprise callers.

clean_string_eval never sets out

The string form never records a return value, even on success. A string eval may be defining subs, opening BEGIN/END blocks, loading modules, or otherwise doing things with no meaningful scalar result. If you need a value back from a string eval, write to an our package variable from inside the string, or wrap a real eval $str inside a clean_eval block and capture from there.

clean_string_eval does not see the caller's lexicals

With a raw eval $string, the eval'd code can see any my variables in the surrounding scope. clean_string_eval cannot: the string is eval'd inside this module, so the caller's lexicals are out of reach. Only package globals are visible.

use Clean::Eval qw/clean_string_eval/;

my $x = 42;
my $ret = clean_string_eval 'print $x';
# $ret is an error: "Global symbol $x requires explicit package name"
# (or, without strict, $x is just an unrelated undef global)

our $y = 42;
clean_string_eval 'print $y';   # prints 42 - $y is a package global

If you need to feed values in, pass them through globals you control or through the environment, or build a closure and use clean_eval with a block instead.

return inside the block returns from the block, not the caller

The block passed to clean_eval is an anonymous subroutine. A return inside it returns from that anonymous subroutine - not from the enclosing named sub - and clean_eval still gets control back and returns 1 for success.

sub do_work {
    my $ok = clean_eval {
        return if $skip;     # returns from the block only
        risky_thing();
    };
    return 0 unless $ok;
    ...
}

This matches the behavior of plain eval { ... }.

Cannot pass a coderef variable with block syntax

The (&) prototype makes clean_eval parse a literal block; it will not accept a coderef in scalar variable form:

my $cref = sub { die "foo" };
clean_eval $cref;          # syntax error / wrong parse

Workarounds:

clean_eval(\&named_sub);   # named sub via \&
clean_eval { $cref->() };  # wrap in a literal block
&Clean::Eval::clean_eval($cref);   # bypass the prototype

SEE ALSO

Try::Tiny, Syntax::Keyword::Try, Feature::Compat::Try.

SOURCE

The source code repository for Clean-Eval can be found at https://github.com/exodist/Clean-Eval/.

MAINTAINERS

AUTHORS

COPYRIGHT

Copyright 2026 Chad Granum exodist7@gmail.com.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://dev.perl.org/licenses/