it-swarm.dev

L'utilisation de goto en vaut-elle la peine?

goto est presque universellement déconseillé. Est-ce que cette déclaration vaut la peine?

30
Casebash

Cela a été discuté plusieurs fois sur Stack Overflow, et Chris Gillum résume les utilisations possibles de goto :

Quitter proprement une fonction

Souvent, dans une fonction, vous pouvez allouer des ressources et devez quitter à plusieurs endroits. Les programmeurs peuvent simplifier leur code en plaçant le code de nettoyage des ressources à la fin de la fonction, tous les "points de sortie" de la fonction se trouveront sur l'étiquette de nettoyage. De cette façon, vous n'avez pas à écrire de code de nettoyage à chaque "point de sortie" de la fonction.

Sortie des boucles imbriquées

Si vous êtes dans une boucle imbriquée et que vous avez besoin de sortir des boucles toutes, un goto peut rendre cela beaucoup plus propre et plus simple que les instructions break et les if-checks.

Améliorations des performances de bas niveau

Ceci n'est valable que dans le code critique, mais les instructions goto s'exécutent très rapidement et peuvent vous donner un coup de pouce lors du déplacement dans une fonction. Il s'agit cependant d'une arme à double tranchant, car un compilateur ne peut généralement pas optimiser le code contenant des gotos.

Je dirais, comme beaucoup d'autres le diraient, que dans tous ces cas, l'utilisation de goto est utilisée comme moyen de sortir d'un coin dans lequel on s'est codé et est généralement un symptôme de code qui pourrait être refactorisé.

51
user8

Les constructions de flux de contrôle de niveau supérieur ont tendance à correspondre aux concepts du domaine problématique. Un if/else est une décision basée sur une condition. Une boucle indique d'effectuer une action à plusieurs reprises. Même une déclaration de rupture dit "nous faisions cela à plusieurs reprises, mais maintenant nous devons arrêter".

Une instruction goto, d'autre part, tend à correspondre à un concept dans le programme en cours d'exécution, pas dans le domaine problématique. Il dit de continuer l'exécution à un point spécifié dans le programme . Quelqu'un qui lit le code doit déduire ce que cela signifie par rapport au domaine problématique.

Bien sûr, toutes les constructions de niveau supérieur peuvent être définies en termes de gotos et de branches conditionnelles simples. Cela ne signifie pas qu'ils ne sont que des gotos déguisés. Considérez-les comme gotos restreints - et ce sont les restrictions qui les rendent utiles. Une instruction break est implémentée comme un saut à la fin de la boucle englobante, mais il vaut mieux la considérer comme opérant sur la boucle dans son ensemble.

Toutes choses étant égales par ailleurs, le code dont la structure reflète celle du domaine problématique a tendance à être plus facile à lire et à maintenir.

Il n'y a aucun cas où une instruction goto est absolument requise (il y a n théorème à cet effet), mais il y a des cas où elle peut être la moins mauvaise solution. Ces cas varient d'une langue à l'autre, selon les constructions de niveau supérieur prises en charge par la langue.

En C, par exemple, je pense qu'il y a trois scénarios de base où un goto est approprié.

  1. Sortir d'une boucle imbriquée. Cela ne serait pas nécessaire si la langue avait une instruction break étiquetée.
  2. Renvoi d'un bout de code (généralement un corps de fonction) en cas d'erreur ou autre événement inattendu. Cela ne serait pas nécessaire si le langage comportait des exceptions.
  3. Implémentation d'une machine à états finis explicite. Dans ce cas (et, je pense, seulement dans ce cas), un goto correspond directement à un concept dans le domaine problématique, passant d'un état à un autre état spécifié, où l'état actuel est représenté par le bloc de code en cours d'exécution. .

D'un autre côté, une machine à états finis explicite peut également être implémentée avec une instruction switch dans une boucle. Cela a l'avantage que chaque état commence au même endroit dans le code, ce qui peut être utile pour le débogage, par exemple.

L'utilisation principale d'un goto dans un langage raisonnablement moderne (qui prend en charge if/else et les boucles) est de simuler une construction de flux de contrôle qui manque dans le langage.

46
Keith Thompson

Cela dépend sûrement du langage de programmation. La principale raison pour laquelle goto a été controversée est à cause de ses effets néfastes qui surviennent lorsque le compilateur vous permet de l'utiliser trop généreusement. Des problèmes peuvent survenir, par exemple, s'il vous permet d'utiliser goto de telle manière que vous pouvez maintenant accéder à une variable non initialisée, ou pire, pour sauter dans une autre méthode et jouer avec la pile des appels. Il devrait être de la responsabilité du compilateur de refuser le flux de contrôle absurde.

Java a tenté de "résoudre" ce problème en interdisant complètement goto. Cependant, Java vous permet d'utiliser return à l'intérieur d'un bloc finally et donc de faire avaler une exception par inadvertance. Le même problème est toujours là: le compilateur est ne fait pas son travail. La suppression de goto de la langue ne l'a pas corrigé.

En C #, goto est aussi sûr que break, continue, try/catch/finally et return. Il ne vous permet pas d'utiliser des variables non initialisées, il ne vous permet pas de sauter d'un bloc enfin, etc. Le compilateur se plaindra. C'est parce qu'il résout le problème réel, qui est comme je l'ai dit le flux de contrôle absurde. goto n'annule pas comme par magie l'analyse d'affectation définitive et d'autres vérifications raisonnables du compilateur.

11
Timwi

Oui. Lorsque vos boucles sont imbriquées à plusieurs niveaux, goto est le moyen niquement de sortir avec élégance d'une boucle interne. L'autre option consiste à définir un indicateur et à sortir de chaque boucle si cet indicateur remplit une condition. C'est vraiment moche et assez sujet aux erreurs. Dans ces cas, goto est tout simplement meilleur.

Bien sûr, l'instruction étiquetée break de Java fait la même chose, mais sans vous permettre de sauter à un point arbitraire dans le code, ce qui résout le problème proprement sans permettre les choses qui rendent goto mauvais.

9
Chinmay Kanchi

La plupart du découragement vient d'une sorte de "religion" qui a été créée autour de Dieu Djikstra qui était convaincante au début des années 60 à propos de son pouvoir aveugle de:

  • sauter n'importe où dans n'importe quel bloc de code
    • fonction non exécutée depuis le début
    • boucles non exécutées depuis le début
    • initialisation de variable ignorée
  • sauter loin de n'importe quel bloc de code sans aucun nettoyage possible.

Cela n'a plus rien à voir avec l'instruction goto des langages modernes, dont l'existence est simplement due à la création de structures de code autres que celles fournies par le langage.

En particulier, le premier point principal ci-dessus est plus autorisé et le second est nettoyé (si vous goto hors d'un bloc la pile est déroulée correctement et tous les destructeurs appropriés appelés)

Vous pouvez vous référer cette réponse pour avoir une idée de la façon dont même le code n'utilisant pas goto peut être illisible. Le problème ne vient pas de lui-même, mais de sa mauvaise utilisation.

Je peux écrire un programme entier sans utiliser if, juste for. Bien sûr, ce ne sera pas bien lisible, un look maladroit et inutilement compliqué.

Mais le problème n'est pas for. C'est moi.

Des choses comme break, continue, throw, bool needed=true; while(needed) {...}, etc. notent plus de mascarade goto pour échapper aux cimeterres des fanatiques djikstrariens, qui -50 ans après l'invention des langues modernes - veulent toujours leurs prisonniers. Ils ont oublié de quoi Djikstra parlait, ils ne se souviennent que du titre de sa note (GOTO considéré comme nuisible, et ce n'était même pas son nouveau titre: il a été modifié par l'éditeur) et blâmer et bash, bash et blâmer chaque contructure ayant ces 4 lettre placée dans l'ordre.

Nous sommes en 2011: il est temps de comprendre que goto doit prendre en compte l'instruction GOTO sur laquelle Djikstra était convaincante.

7
Emilio Garavaglia

Le goto impair ici ou là, tant qu'il est local à une fonction, nuit rarement de manière significative à la lisibilité. Il en profite souvent en attirant l'attention sur le fait qu'il se passe quelque chose d'inhabituel dans ce code qui nécessite l'utilisation d'une structure de contrôle quelque peu inhabituelle.

Si les gotos (locaux) nuisent considérablement à la lisibilité, cela signifie généralement que la fonction contenant le goto est devenue trop complexe.

Le dernier goto que j'ai mis dans un morceau de code C était de construire une paire de boucles de verrouillage. Il ne rentre pas dans la définition normale de l'utilisation "acceptable", mais la fonction est finalement devenue beaucoup plus petite et plus claire. Pour éviter le goto, il aurait fallu une violation particulièrement désordonnée de DRY.

4
blucz

Je pense que toute cette question a consisté à aboyer le mauvais arbre.

GOTO en tant que tel ne me semble pas problématique, mais il s'agit plutôt très souvent d'un symptôme d'un véritable péché: le code spaghetti.

Si le GOTO provoque un croisement majeur des lignes de contrôle de flux, alors c'est mauvais, point final. S'il ne traverse aucune ligne de contrôle de débit, il est inoffensif. Dans la zone grise entre les deux, nous avons des choses comme les renflouements de boucle, il y a encore des langages qui n'ont pas ajouté de constructions qui couvrent tous les cas gris légitimes.

Le seul cas où je me suis retrouvé à l'utiliser effectivement depuis de nombreuses années est le cas de la boucle où le point de décision est au milieu de la boucle. Vous vous retrouvez avec un code en double, un drapeau ou un GOTO. Je trouve que la solution GOTO est la meilleure des trois. Il n'y a pas de croisement de lignes de contrôle de flux ici, c'est inoffensif.

3
Loren Pechtel

Oui, le goto peut être utilisé pour bénéficier de l'expérience du développeur: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

Cependant, comme pour tout outil puissant (pointeurs, héritage multiple, etc.), il faut être discipliné en l'utilisant. L'exemple fourni dans le lien utilise PHP, ce qui limite l'utilisation de la construction goto à la même fonction/méthode et désactive la possibilité de sauter dans un nouveau bloc de contrôle (par exemple, boucle, instruction switch, etc.)

1
AdamJonR

Dépend de la langue. Il est encore largement utilisé dans la programmation Cobol, par exemple. J'ai également travaillé sur un appareil Barionet 50, dont le langage de programmation du micrologiciel est un ancien dialecte BASIC qui, bien sûr, vous oblige à utiliser Goto.

1
user16764

Je dirais non. Si vous trouvez la nécessité d'utiliser GOTO, je parie qu'il est nécessaire de repenser le code.

0
Walter

goto peut être utile lors du portage du code assembleur hérité vers C. Dans le premier cas, une conversion instruction par instruction en C, en utilisant goto en remplacement de l'assembleur branch l'instruction, peut permettre un portage très rapide.

0
Graham Borland