Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Try::Tiny or Eval? [closed]

Tags:

perl

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?

like image 893
ado Avatar asked Aug 02 '13 09:08

ado


1 Answers

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 $_

like image 189
Borodin Avatar answered Sep 28 '22 07:09

Borodin