Using Try::Tiny or Eval?

perl

Solution

Update

Thanks to an anonymous user I have been able to correct a bug in my answer. The `return` in the `catch` block wasn't having the desired effect, as it returned only from the `catch` subroutine.

If there was no exception, `try` returns the value of the `try` block, otherwise the value of the `catch` block. So this version correctly executes and returns the value of `$c->redirect("/index")` if the `insert` succeeded, otherwise it calls and returns the value of `$c->show_error($_)`.

sub insert_exec {
  my ($self, $c, $args) = @_;
  my ($params, $table, $model) = $self->_init({context => $c, args => $args});
  try {
    $model->insert($table, $params);
    $c->redirect("/index");
  }
  catch {
    $c->show_error($_);
  };
}
  

`Try::Tiny` is pretty much essential as error handling with `eval` is very hard indeed to get right in the general case. The module's documentation says this

This module provides bare bones try/catch/finally statements that are designed to minimize common mistakes with eval blocks, and NOTHING else.

The main focus of this module is to provide simple and reliable error handling for those ... who still want to write correct eval blocks without 5 lines of boilerplate each time.

Your code would look like this

use Try::Tiny;

sub insert_exec {
  my ($self, $c, $args) = @_;
  my ($params, $table, $model) = $self->_init({context => $c, args => $args});
  try {
    $model->insert($table, $params);
  }
  catch {
    return $c->show_error($_);
  };
  $c->redirect("/index");
}

which I hope you'll agree is much nicer.

Two points are notable:

`try` and `catch` are subroutines coded to look like language words. That means a semicolon after the final closing brace is essential.

For the same reason, `return` within the `try` or `catch` blocks will not work as expected, and will simply exit the block, returning to the parent subroutine. See my update above.

Within the `catch` block `$@` has its original value from before the `try`. The value resulting from the error is in `$_`

Problem

Which is safer & better & cleaner & more recommended to use? I used: ``` sub insert_exec { my ($self, $c, $args) = @_; my ($params, $table, $model) = $self->_init({context => $c, args => $args}); eval { $model->insert($table, $params); }; if ($@) { return $c->show_error($@); } ## error $c->redirect("/index"); } ``` But for this kind of cases (see the error part), I have been told that using Try::Tiny is better? My question is: How would you write this and why would you choose that way?

Original source