Wird Try :: Tiny weiterhin für die Ausnahmebehandlung in Perl 5.14 oder höher empfohlen?


76

Der Konsens der Perl-Community scheint zu sein, dass dies Try::Tinyder bevorzugte Weg ist, um mit Ausnahmen umzugehen.

Perl 5.14 (die Version, die ich verwende) scheint die Probleme mit evaldiesen Try::TinyAdressen zu lösen . Wird es Try::Tinymir noch Vorteile bringen?


6
Ich bin auch an der Antwort der Community interessiert! Gute Frage!
Joel Berger

Antworten:


34

Meine Antwort ist unbeliebt, aber ich denke nicht, dass Perl-Programmierer versuchen sollten, die äußerst schlechte Vorstellung von dem zu verwenden, was wir in Perl "Ausnahmen" nennen. Dies ist im Wesentlichen ein Seitenkanal-Rückgabewert. Trotz der Komplexität der Verwendung einer globalen Variablen zur Weitergabe von Zuständen sind die Menschen immer noch verliebt in die Idee von Ausnahmen und versuchen immer wieder, sie zum Laufen zu bringen.

In der Praxis diesignalisieren Menschen jedoch Fehler. Einige werden sagen, dass Sie diemit einer Referenz Fehlerobjekte zurückgeben können, aber das brauchen Sie nicht die. Wir haben Objekte, also sollten wir die ganze Kraft von Objekten nutzen:

 sub some_sub {
    ...
    return Result->new( error => 1, description => ... ) if $something_went_wrong;
    return Result->new( error => 0, ... );
    }

 my $result = some_sub( ... );
 if( $result->is_error ) { ... };

Dies beinhaltet keine globalen Variablen, Fernaktionen, Kopfschmerzen oder spezielle Specials. Sie erstellen eine winzige Klasse Resultoder wie auch immer Sie sie nennen möchten, um Ihre Rückgabewerte so zu verpacken, dass Sie strukturierte Daten anstelle einzelner Werte ohne Identität haben. Sie fragen sich nicht mehr, was ein Rückgabewert bedeutet. Ist das undefein realer Wert oder ein Hinweis auf ein Versagen? Ist der Rückgabewert gut, wenn er definiert ist oder wahr ist? Ihr Objekt kann Ihnen diese Dinge sagen. Und Sie können dasselbe Objekt mit verwenden die. Wenn Sie das Objekt bereits mit dieund als Rückgabewert verwenden, gibt es sehr wenig zu empfehlen, all die zusätzlichen Dinge, die Sie tun müssen, um zu tolerieren $@.

Ich spreche mehr darüber in "Fehlerobjekte zurückgeben, anstatt Ausnahmen auszulösen".

Ich weiß jedoch, dass Sie nicht helfen können, was andere Leute tun, also müssen Sie immer noch so tun, als hätte Perl Ausnahmen.


2
Ich stimme zu, aber wie Sie am Ende sagten, gibt es Module, die, diewenn sie nicht sollten, so dass wir immer noch wissen müssen, welcher Mechanismus diese Ausnahmen abfängt. Zukünftige Modulentwickler sollten diesen Ansatz berücksichtigen!
Joel Berger

6
Sehr gute Lösung, aber Die / Exception hat einen großen Vorteil: Weitergabe über Sub Calls Stack. Ich meine: Testen Sie nicht, ob ein Unterprogrammaufruf bestanden oder nicht bestanden wurde - fangen Sie einfach keine Ausnahme ab. Es wird sich ausbreiten, bis jemand es fängt.
Msztolcman

2
Dieses Propagierungsmaterial ist eine sehr schlechte Art, ein Programm zu entwerfen. Was sollen diese höheren Ebenen tun, um einen Fehler zu behandeln? In Perl können Sie nicht damit umgehen und dort weitermachen, wo Sie aufgehört haben, sodass Sie überhaupt nicht wirklich damit umgehen. Die Methode, die ich zeige, kann sich genauso gut verbreiten. Jedes Level kann zu dem Ergebnis beitragen, das es erhält und weitergibt.
Brian D Foy

8
Sehr arm? Das glaube ich nicht. Fehler sollten dort behandelt werden, wo wir sagen können, was mit ihnen zu tun ist. Viele der Fehler sollten nicht behandelt werden - nur protokolliert werden und dem Benutzer eine Meldung anzeigen (dies muss in der GUI erfolgen, nicht in Funktionen der untersten Ebene). Es ist nur eine Designannahme und hat einige Vor- und Nachteile (wie immer).
Msztolcman

6
Ich kann verstehen, warum Sie Ihre Argumente vorbringen, aber es erfordert, dass ein Programmierer nie vergisst, nach Fehlern zu suchen. Wir wissen, dass sie es sollten, aber was wir theoretisch und in der Praxis tun sollten, wenn wir unter der Waffe einer engen Frist stehen, ist nicht dasselbe. Daher könnten wir vergessen, nach diesem einen kritischen Fehler zu suchen und unseren Code weiterlaufen zu lassen, ohne zu wissen, dass er seine Daten überall beschädigt.
Ovid

31

Es war immer ein Fall persönlicher Präferenz. Bevorzugen Sie

my $rv;
if (!eval { $rv = f(); 1 } ) {
   ...
}

oder

my $rv = try {
   f();
} catch {
   ...
};

Aber denken Sie daran, dass letzteres anon subs verwendet, so dass es sowohl mit returnals auch nextund dergleichen herumspielt . Try :: Tinys Try-Catch ist möglicherweise weitaus komplizierter, wenn Sie Kommunikationskanäle zwischen dem Catch-Block und außerhalb des Catch-Blocks hinzufügen.

Das beste (einfachste) Szenario für die Rückgabe einer Ausnahme ist, wenn dies $rvimmer der Fall ist, wenn keine Ausnahme vorliegt. Es würde wie folgt aussehen:

my $rv;
if ($rv = eval { f() }) {
   ...
   return;
}

vs.

my $rv = try {
   f();
} catch {
   ...
};

if (!$rv) {
   return;
}

Deshalb würde ich TryCatch anstelle von Try :: Tiny verwenden, wenn ich ein solches Modul verwenden würde.

Die Änderung zu Perl bedeutet einfach, dass Sie es if ($@)erneut tun können. Mit anderen Worten,

my $rv;
if (!eval { $rv = f(); 1 } ) {
   ...
}

kann geschrieben werden

my $rv = eval { f() };
if ($@) {
   ...
}

4
Wenn Sie den von der Auswertung zurückgegebenen Wert nicht abfangen müssen (was zumindest für mich der häufigste Fall ist), wird die Auswertungsversion etwas einfacher.
Zby

TryCatch hat weit weniger Einschränkungen als Try :: Tiny und ist viel schneller. Es gibt eine Einschränkung, es ist abscheulich langsam zu laden.
Schwern

@Schwern, Eine auf Devel :: CallParser basierende Lösung sollte schneller geladen werden.
Ikegami

@ikegami Nein, das Problem ist das Vertrauen in Moose und Parse :: Method :: Signatures (der Mut von MooseX :: Method :: Signatures).
Schwern

@Schwen, deshalb würde Devel :: CallParser helfen. Damit können Sie die perlintegrierten Parsing-Funktionen verwenden.
Ikegami

14

Wenn nichts anderes, Try::Tinyist immer noch schöner syntaktischer Zucker. Wenn Sie etwas Schwergewichtiges wünschen, gibt es auch TryCatcheinige, die einige Probleme im Zusammenhang mit der Tatsache lösen, dass die Klauseln in Try::TinyUnterroutinen sind (zum Beispiel, dass returndie einschließende Funktion nicht verlassen wird).


11

Try::Tinyist einfach und leicht. Zu einfach. Wir hatten zwei Probleme:

  • anonyme Subs - es gab immer Probleme mit der ' return' Anweisung im Inneren
  • immer und alles fangen

Also habe ich einige Änderungen vorgenommen Try::Tiny, die uns helfen. Jetzt haben wir:

try sub {},
catch 'SomeException' => sub {},
catch [qw/Exception1 Exception2/] => sub {},
catch_all sub {};

Ich weiß - diese Syntax ist ein wenig exotisch, aber dank offensichtlichem ' sub' wissen unsere Programmierer jetzt, dass returndie Anweisung ' ' nur vom Ausnahmebehandler beendet wird und wir immer nur diese Ausnahmen abfangen, die wir abfangen möchten :)


1
Beachten Sie, dass Sie sub{}ohne Änderung zu Try :: Tiny:perl -MTry::Tiny -E"&try(sub { say 'A'; die qq{B\n} if $ARGV[0] }, &catch(sub { print; }));" 1
Ikegami

2
Beachten Sie jedoch, dass andere Module (z. B. TryCatch ) echte Blöcke verwenden, keine anon subs, um das Rauschen zu vermeiden.
Ikegami

1
Es gibt keine Möglichkeit, nicht alles in Perl
abzufangen

2
@hobbs: natürlich :) aber wenn ein erneutes Werfen ohne Ihre Teilnahme erfolgt ... ist es viel besser;) Das Wichtigste hier ist ein anderes Schlüsselwort zum Abfangen aller Ausnahmen als zum Abfangen nur einiger von ihnen :)
msztolcman

3
Kommt darauf an, was du mit Licht meinst. In Bezug auf die CPU verliert Try :: Tiny stark. Andererseits weist TryCatch komplexere Abhängigkeiten auf.
Ikegami

0

Entweder tun:

local $@;
eval { … }

… Um zu verhindern, dass Änderungen an $ @ den globalen Bereich beeinflussen, oder verwenden Sie Try :: Tiny.

Syntaktisch gibt es Situationen, in denen ich das eine oder andere bevorzuge.


0

Try :: Tiny ist großartig, erfordert jedoch ein Semikolon in der letzten Klammer und erlaubt nicht die Verwendung der Zuweisung von Ausnahmevariablen und geschweige denn das Abfangen von Ausnahmeklassen. TryCatch hat früher großartige Arbeit geleistet, wurde jedoch mit der neuen Version 0.006020 von Devel :: Declare gebrochen . Eine weitere großartige Implementierung ist Syntax :: Keyword :: Try , implementiert jedoch keine Zuweisungen von Ausnahmevariablen oder das Abfangen von Ausnahmeklassen.

Es gibt ein neues Modul Nice :: Try , das ein perfekter Ersatz ist.

Es ist nicht erforderlich, ein Semikolon auf der letzten Klammer wie Try :: Tiny zu haben.

Sie können auch Ausnahmevariablen wie zuweisen

  try
  {
    # something
  }
  catch( $e )
  {
    # catch this in $e
  }

Es funktioniert auch mit Klassenausnahmen wie

  try
  {
    # something
  }
  catch( Exception $e )
  {
    # catch this in $e
  }

Und es unterstützt auch finally. Seine Funktionen machen es ziemlich einzigartig.

Vollständige Offenlegung: Ich habe dieses Modul entwickelt, als TryCatch kaputt ging.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.