2009-09-15 8 views
3

Comment gérer les exceptions dans un langage procédural comme C ou Perl? (Je sais que Perl fait aussi OO.) Quelle est la meilleure façon de gérer l'exception dans le code de procédure en Perl?Comment gérer les exceptions dans un langage procédural?

+5

Une programmation suffisante en Perl est une * programmation procédurale *, mais cela n'en fait pas un langage * procédural *. C'est un langage multi-paradigme. Il permet la programmation OO, mais il emprunte aussi des langages de programmation * fonctionnels *. La seule chose que je ne pense pas pouvoir faire sans beaucoup de travail est la programmation * logique * (comme Prolog). Où 'C' est un langage procédural, et le plus proche que vous pouvez obtenir est en pratiquant et en appliquant la méthodologie des types de données abstraites. – Axeman

+0

@Axeman, voir la distribution AI :: Prolog sur CPAN: http://search.cpan.org/~jjore/AI-Prolog/lib/AI/Prolog.pm – friedo

Répondre

1

Cela dépend plutôt de ce que vous entendez par «gestion des exceptions».

Certains systèmes d'exploitation ont des mécanismes d'exception - voir Windows exception handling routines ou Linux signal handlers (dont certains sont des exceptions). Si vous voulez dire l'idiome dans le code utilisateur pour signaler une erreur et dérouler la pile en nettoyant les objets alloués, alors le code C n'appelle pas les destructeurs sur les objets alloués quand la pile est déroulée (elle récupère juste la mémoire), il est donc normal en C que les fonctions retournent une valeur d'état, et que le code appelant fasse le nettoyage requis avant de retourner. Je ne connais pas bien Perl, mais Google pour "gestion des exceptions Perl" indique qu'il a à la fois des mécanismes intégrés équivalents à try/catch et des modules qui donnent une gestion des exceptions de type "OO".

0

L'approche traditionnelle est ... eh bien ... pas :)

En général, les gens se contentent de vérifier l'état après avoir essayé quelque chose, et si quelque chose a mal tourné, ils nettoient et retourner un code d'erreur, plutôt que de continuer. Cette erreur contrôle et de retour se propage vers le bas de la pile d'appel de fonction jusqu'à ce qu'il revienne à un endroit de haut niveau dans votre programme, où vous soin d'informer l'utilisateur au lieu de simplement revenir plus d'erreurs:

int try_it() { 
    if (!do_something(...)) { 
    return TRYIT_FAILURE; 
    } 
} 

void my_gui() { 
    rc = try_it() 
    if (rc == TRYIT_FAILURE) { 
    message_box("failed when trying it.", MB_ABORT|MB_RETRY); 
    } 
    ... 
} 

Vous pouvez également faire cela dans une grande fonction, en utilisant ifs imbriqués, si vous voulez quelque chose comme un essai ... sauf construction:

if (stage1()) { 
    if (stage2()) { 
     if(stage3()) { 
      printf("success!\n"); 
     } else { 
      // error handling for stage 3 
     } 
    } else { 
     // error handling for stage 2 
    } 
} else { 
    // error handling for stage 1 
} 

Et vous pouvez faire la même chose avec GOTO si vous êtes un peu fou.

Cependant, vous pouvez faire des exceptions réelles, au moins en C. C a deux appels de bibliothèque standard pour ce genre de chose: setjmp et longjmp. Avec ceux-ci, vous pouvez revenir en arrière à travers plusieurs appels de fonction à un endroit prédéterminé, où vous savez que l'exception (saut) s'est produite. Voir Setjmp.h#exception_handling on wikipedia pour plus d'informations à ce sujet.

Il semble que Perl ait un moyen de le faire, même si cela me semble loin d'être intuitif. Là encore, je ne suis pas le code en Perl :)

Perl FAQ Q4.8

+0

-1 Les développeurs Perl utilisent très certainement des exceptions. Je dirais qu'ils sont plus importants dans un langage dynamique comme Perl que dans un langage comme Java ou C++; –

1

En C il y avait setjmp et longjump; Pour l'essentiel, setjmp() enregistre le contexte actuel dans la pile, et longjmp() peut revenir au point sauvegardé par setjmp(). L'entrée wikipedia sur ces remplit joliment les détails.

7

En Perl 5, la gestion des exceptions est effectuée en utilisant eval et die. Vous évaluez simplement le corps du code et s'il meurt, vous pouvez inspecter [email protected] pour l'erreur. Ce n'est pas si simple si vous voulez le faire correctement, c'est pourquoi les différents modules try/catch existent. Vous pourriez être intéressé par Try::Tiny qui n'a pas de dépendances et décrit tous les pièges que vous avez à traiter lorsque vous utilisez la gestion des exceptions eval naïf. (Voir aussi this blog post par l'auteur de Try :: Tiny.)

+0

"eval" a des pénalités de performance qui peuvent le rendre prohibitif pour les systèmes à grande échelle. – DVK

+4

@DVK, parlez-vous de chaîne eval ou bloc eval? Les problèmes avec l'évaluation de chaîne sont bien connus, mais la gestion des exceptions avec eval utilise généralement l'évaluation de bloc. Si vous dites qu'il y a des problèmes de performance avec Block Eval, pouvez-vous fournir une source ou une démonstration du problème? – daotoad

+2

Pour ce que ça vaut, http://gist.github.com/187483. – zoul

2

Voici un exemple de la façon dont je fais des exceptions en Perl (sans utiliser l'un des modules Try):

use Carp; 
use English qw(-no_match_vars); 

do_something_needing_rollback_if_failed(); 
eval { 
    do_something_dangerous(); 
} or do { 
    # Exception was thrown by dangerous method 
    # Save the error: 
    my $error = $EVAL_ERROR; 

    # Try to rollback 
    eval { rollback(); } 
    or do { confess qq{Couldn't rollback: $EVAL_ERROR. Original error $error}; } 

    # Let's rethrow: 
    confess qq{Rolled back! Error was $error}; 
} 

L'une des parties les plus gênants de la gestion des exceptions Perl est-il utilise une seule variable pour stocker toute erreur d'exception, et il peut être accidentellement écrasé, donc un codage défensif est requis.

1

En Perl, comme d'habitude, il y a plusieurs façons de le faire. Cependant, la communauté des développeurs a dans l'ensemble choisi la bonne façon de faire la plupart des choses.

Je suis de plus en plus fan de Exception::Base.

Si vous souhaitez une implémentation plus légère, utilisez simplement Carp.

Vous piègez des exceptions à l'aide d'une construction eval { ... }; if ([email protected]) { ... }.

Avec Exception :: Base, il offre un moyen d'extraire la construction if ([email protected]) { ... } pour vous. Cependant, vous devrez toujours utiliser eval { ... }.

Questions connexes