web-dev-qa-db-fra.com

Instruction Switch avec des retours - exactitude du code

Disons que j'ai un code en C avec approximativement cette structure:

switch (something)
{
    case 0:
      return "blah";
      break;

    case 1:
    case 4:
      return "foo";
      break;

    case 2:
    case 3:
      return "bar";
      break;

    default:
      return "foobar";
      break;
}

Évidemment, les "ruptures" ne sont pas nécessaires pour que le code s'exécute correctement, mais cela ressemble à une mauvaise pratique si je ne les mets pas pour moi.

Qu'est-ce que tu penses? Est-ce bien de les enlever? Ou les garderiez-vous pour une "exactitude" accrue?

73
houbysoft

Supprimez les instructions de pause. Ils ne sont pas nécessaires et certains compilateurs émettront peut-être des avertissements de "code inaccessible".

107
kgiannakakis

Je prendrais une approche différente entièrement. Ne revenez pas au milieu de la méthode/fonction. À la place, placez simplement la valeur de retour dans une variable locale et envoyez-la à la fin.

Personnellement, je trouve ce qui suit plus lisible:

String result = "";

switch (something) {
case 0:
  result = "blah";
  break;
case 1:
  result = "foo";
  break;
}

return result;
28
NotMe

Personnellement, je supprimerais les retours et garderais les pauses. J'utiliserais l'instruction switch pour attribuer une valeur à une variable. Retournez ensuite cette variable après l'instruction switch.

Bien que ce soit un point discutable, j'ai toujours pensé qu'une bonne conception et une bonne encapsulation signifiaient une entrée et une sortie. Il est beaucoup plus facile de garantir la logique et vous ne manquerez pas accidentellement de code de nettoyage basé sur la complexité cyclomatique de votre fonction.

Une exception: le retour anticipé est acceptable si un paramètre incorrect est détecté au début d’une fonction, avant l’acquisition de toutes les ressources.

8
Amardeep AC9MF

Conservez les pauses - vous risquez moins de rencontrer des problèmes si/lorsque vous modifiez le code ultérieurement si les pauses sont déjà en place.

Cela dit, beaucoup (y compris moi) considèrent que revenir au milieu d'une fonction est une mauvaise pratique. Idéalement, une fonction devrait avoir un point d'entrée et un point de sortie. 

5
Paul R

Retirez-les. Il est idiomatique de renvoyer des instructions case, et c'est du bruit de "code inaccessible" sinon.

5
Stephen

Je les enlèverais. Dans mon livre, un code mort comme celui-là devrait être considéré comme une erreur, car cela vous oblige à faire une double-prise et à vous demander "Comment pourrais-je jamais exécuter cette ligne?"

4
Hank Gay

J'écrirais normalement le code sans eux. OMI, code mort a tendance à indiquer la négligence et/ou un manque de compréhension.

Bien sûr, je considérerais aussi quelque chose comme:

char const *rets[] = {"blah", "foo", "bar"};

return rets[something];

Edit: même avec le post édité, cette idée générale peut fonctionner correctement:

char const *rets[] = { "blah", "foo", "bar", "bar", "foo"};

if ((unsigned)something < 5)
    return rets[something]
return "foobar";

À un moment donné, en particulier si les valeurs d'entrée sont clairsemées (par exemple, 1, 100, 1000 et 10000), vous souhaitez plutôt un tableau épars. Vous pouvez implémenter cela raisonnablement comme un arbre ou une carte (bien que, bien sûr, un commutateur fonctionne également dans ce cas également).

4
Jerry Coffin

Qu'est-ce que tu penses? Est-ce bien de les enlever? Ou les garderiez-vous pour une "exactitude" accrue?

C'est bien de les enlever. Utiliser return est exactement le scénario dans lequel break ne doit pas être utilisé. 

2
OscarRyz

Je dirais les supprimer et définir un défaut: branche.

2
Bella

Ne serait-il pas préférable d'avoir un tableau avec

arr[0] = "blah"
arr[1] = "foo"
arr[2] = "bar"

et faire return arr[something];?

S'il s'agit de la pratique en général, vous devriez conserver les instructions break dans le commutateur. Si vous n'avez pas besoin d'énoncés return dans le futur, le risque de passer à la prochaine case diminue.

2
Vivin Paliath

Pour "exactitude", une seule entrée, des blocs de sortie simples sont une bonne idée. Au moins ils l'étaient quand j'ai obtenu mon diplôme en informatique. Donc, je déclarerais probablement une variable, l'assigner dans le commutateur et revenir une fois à la fin de la fonction

2
Steve Sheldon

Intéressant. Le consensus de la plupart de ces réponses semble être que la déclaration redondante break est un fouillis inutile. D'autre part, j'ai lu l'instruction break dans un commutateur comme étant la «clôture» d'une affaire. Les blocs case qui ne se terminent pas par un break ont tendance à me sauter dessus comme une chute potentielle malgré des bugs.

Je sais que ce n'est pas comme ça quand il y a une return au lieu d'une break, mais c'est ainsi que mes yeux «lisent» le casse d'un commutateur, donc personnellement, je préférerais que chaque case soit associé à un break. Mais de nombreux compilateurs se plaignent de ce que la break après une return soit superflue/inaccessible, et apparemment, il semble que je sois dans la minorité de toute façon.

Donc, débarrassez-vous de la break après une return.

NB: tout ceci ignore si la violation de la règle d’entrée/sortie unique est une bonne idée ou non. En ce qui me concerne, j’ai une opinion qui change malheureusement en fonction des circonstances ...

1
Michael Burr

Je pense que les * break * s ont un but. C'est maintenir l'idéologie de la programmation. Si nous ne voulons que "programmer" notre code sans cohérence logique, il sera peut-être lisible maintenant, mais essayez demain. Essayez de l'expliquer à votre patron. Essayez de l'exécuter sur Windows 3030.

Bleah, l'idée est très simple:


Switch ( Algorithm )
{

 case 1:
 {
   Call_911;
   Jump;
 }**break**;
 case 2:
 {
   Call Samantha_28;
   Forget;
 }**break**;
 case 3:
 {
   Call it_a_day;
 }**break**;

Return thinkAboutIt?1:return 0;

void Samantha_28(int oBed)
{
   LONG way_from_right;
   SHORT Forget_is_my_job;
   LONG JMP_is_for_Assembly;
   LONG Assembly_I_work_for_cops;

   BOOL allOfTheAbove;

   int Elligence_says_anyways_thinkAboutIt_**break**_if_we_code_like_this_we_d_be_monkeys;

}
// Sometimes Programming is supposed to convey the meaning and the essence of the task at hand. It is // there to serve a purpose and to keep it alive. While you are not looking, your program is doing  // its thing. Do you trust it?
// This is how you can...
// ----------
// **Break**; Please, take a **Break**;

/ * Juste une question mineure cependant. Combien de café avez-vous eu en lisant ce qui précède? IL. Pauses le système parfois * /

0
Cruentos Solum

Si vous avez le type de code "lookup", vous pouvez conditionner la clause switch-case dans une méthode par elle-même.

J'ai quelques-uns d'entre eux dans un système de "hobby" que je développe pour le plaisir:

private int basePerCapitaIncomeRaw(int tl) {
    switch (tl) {
        case 0:     return 7500;
        case 1:     return 7800;
        case 2:     return 8100;
        case 3:     return 8400;
        case 4:     return 9600;
        case 5:     return 13000;
        case 6:     return 19000;
        case 7:     return 25000;
        case 8:     return 31000;
        case 9:     return 43000;
        case 10:    return 67000;
        case 11:    return 97000;
        default:    return 130000;
    }
}

(Oui. C'est l'espace GURPS ...)

Je conviens avec d’autres que vous devriez, dans la plupart des cas, éviter plus d’un retour dans une méthode et je reconnais que celle-ci aurait peut-être été mieux implémentée sous forme de tableau ou autre. Je viens de trouver que switch-case-return est une correspondance assez facile avec une table de correspondance avec une corrélation de 1-1 entre entrée et sortie, comme ci-dessus (les jeux de rôle en sont pleins, je suis sûr qu'ils existent dans d'autres "entreprises" aussi): D

D'un autre côté, si la clause case est plus complexe ou si quelque chose se produit après l'instruction-switch, je ne recommanderais pas d'utiliser return, mais plutôt de définir une variable dans le commutateur, de la terminer par une pause et de la renvoyer. la valeur de la variable à la fin.

(D'un autre côté, vous pouvez toujours modifier le passage à une méthode différente. Je doute que cela ait un impact sur les performances. Je ne serais pas surpris si les compilateurs modernes pouvaient même le reconnaître. quelque chose qui pourrait être en ligne ...)

0
Erk

J'ai personnellement tendance à perdre les breaks. Une des sources de cette habitude provient peut-être des procédures de fenêtre de programmation pour les applications Windows:

LRESULT WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_SIZE:
            return sizeHandler (...);
        case WM_DESTROY:
            return destroyHandler (...);
        ...
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Personnellement, je trouve cette approche beaucoup plus simple, succincte et flexible que de déclarer une variable de retour définie par chaque gestionnaire, puis de la renvoyer à la fin. Compte tenu de cette approche, les breaks sont redondants et devraient donc disparaître - ils ne servent à rien (syntaxiquement ou visuellement à l'OMI) et ne font que gonfler le code.

0
Mac

Code de sortie à un moment donné. Cela permet une meilleure lisibilité du code. L'ajout d'instructions de retour (sorties multiples) entre elles rendra le débogage difficile.

0
Clarice

Je dis les enlève. Si votre code est si illisible que vous devez coller des pauses "pour plus de sécurité", vous devriez reconsidérer votre style de codage :)

De plus, j'ai toujours préféré ne pas mélanger les pauses et les retours dans l'instruction switch, mais plutôt m'en tenir à l'une d'entre elles.

0
Thomas Kjørnes