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:

      * It modifies the global $@, which can be clobbered by destructors or
      other code running during stack unwind, leading to lost or corrupted
      error messages.

      * The return value of eval can be ambiguous: a successful eval that
      legitimately returns a false value is indistinguishable from a
      failure unless you check $@.

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

    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).

SYNOPSIS

        use Clean::Eval qw/clean_eval clean_string_eval last_error/;
    
        # Block form
        if (my $ret = clean_eval { do_something_risky() }) {
            # success path - $ret is a true value (1)
        }
        else {
            # failure path - $ret is the error object
            warn "Failed: $ret\n";          # stringifies to error message
            warn "  at $ret->{file} line $ret->{line}\n";
        }
    
        # String form (compiles at runtime). No need to add a trailing
        # "; 1" - it is appended for you so the success path is unambiguous.
        my $ret = clean_string_eval 'use SomeOptionalModule';
        unless ($ret) {
            warn "Optional dep missing: $ret\n";
        }
    
        # Retrieve the most recent error 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/;

    $ret = clean_eval { BLOCK }

      Run BLOCK under eval. On success returns 1. On failure returns a
      Clean::Eval error object (see "ERROR OBJECT"). $@ in the caller's
      scope is not touched.

      The prototype is (&), so the block form works without a leading sub.

    $ret = clean_string_eval $STRING

      Run $STRING as Perl code under eval. On success returns 1. On failure
      returns a Clean::Eval error object.

      A #line directive is prepended to $STRING using the caller's filename
      and line number, so any error or warning produced by the eval'd code
      refers to the source location of the clean_string_eval call rather
      than to an anonymous eval string.

      A trailing ; 1 is also appended to $STRING, so you do not need to
      remember the usual eval "...; 1" success guard - the return value is
      unambiguously 1 on success regardless of what the final statement in
      $STRING evaluates to. Including the ; 1 yourself is harmless.

      The prototype is ($), so a single scalar argument is taken.

    $err = last_error()

      Return the most recent error object produced by clean_eval or
      clean_string_eval anywhere in the program, or undef if no error has
      been recorded yet. Useful for code paths that discarded the return
      value or want to inspect a previous failure after the fact.

      Caveat: last_error is a global slot and is subject to the same class
      of bug that makes raw $@ fragile. If a DESTROY method (or anything
      else running during stack unwind) calls clean_eval or
      clean_string_eval, it will overwrite the global and the error you
      actually cared about will be lost. last_error is a convenience, not a
      guarantee - the only robust way to inspect a particular failure is to
      capture the return value of clean_eval/clean_string_eval directly at
      the call site and keep it in a lexical of your own.

ERROR OBJECT

    On failure both clean_eval and clean_string_eval return a blessed
    hashref of class Clean::Eval. It overloads stringification and boolean
    context:

      * Boolean context: always false. This lets if (my $ret = clean_eval {
      ... }) work without ambiguity even when the block legitimately
      returns a false value.

      * String context: the trapped error (the value $@ had inside the
      eval).

    The object is a plain hashref with the following keys:

    error

      The trapped error message (string or object).

    package

      The package the call was made from.

    file

      The file the call was made from.

    line

      The line the call was made from.

    An additional to_string method is provided that returns the error
    message; it is equivalent to stringifying the object.

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.

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

    Chad Granum <exodist@cpan.org>

AUTHORS

    Chad Granum <exodist@cpan.org>

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/

