Journal Is return the new goto ?

Posté par  (site web personnel, Mastodon) . Licence CC By‑SA.
Étiquettes :
13
26
jan.
2024

Mon cher journal,

Depuis quelques années maintenant je m'initie à de «nouveaux» langages comme le Scala et le Rust.

Ces deux langages sont assez différents mais essaient tous les deux d'intégrer des principes issus de programmation fonctionnelle.

Un des concept intégré à ces deux langages est celui de se passer du mot clef return pour retourner la valeur.

La dernière ligne à la fin de la fonction faisant office de valeur retournée.

scala> def pof(i: Int) : Int = { i + 1 };
pof: (i: Int)Int

scala> pof(1)
res0: Int = 2

scala> def pif(i: Int) : Int = {
     | val pouf : Int = i - 1;
     | pouf + 1
     | }
pif: (i: Int)Int

scala> pif(1)
res1: Int = 1

scala> def pouet(i: Int) : Int = {
     | if(i == 0 ){return -1}
     | i
     | }
pouet: (i: Int)Int

scala> pouet(0)
res2: Int = -1

Remarquez qu'en Scala on peut tout de même l'utiliser, mais c'est déconseillé.

Mais pourquoi donc ce délit de sale gueule ? Le bannissement de return ne serait-il pas un nouveau totem comme le fut le bannissement du goto en son temps ?

  • # très bonne question

    Posté par  . Évalué à 10.

    Très bonne question. Quand on me laisse le droit de le faire (codé est de plus en plus une activité collective) j'utilise goto (language C) pour tous ce qui est gestion d'erreur au sein de ma fonction, pour désinitialiser mes allocations par example. Cela permet d'avoir un code "linéaire" avec peu de profondeur par rapport à un enfer de if/else en profondeur.

    Le seul truc que j'ai trouvé de mieux c'est les "defer" à la golang ou swift, que j'aimerai beaucoup avoir dans une futur version de C.

  • # Tu peux faire les questions et les réponses...

    Posté par  . Évalué à 9.

    En fait, si tu parles de "totem" et que tu affirmes que le code était meilleur avec des "goto", tu fais les questions et les réponses. En gros, tu es en désaccord avec les concepteurs de ces langages, et voila.

    Parmi les avantages de ce système, tu as un allègement de la syntaxe (plus besoin de "return"), une écriture plus intuitive des fonctions à une ligne (type fonctions mathématiques), style "int square(x) x*x ", et une diminution très forte des bugs de post-conditions (par exemple si tu as un if(answer < 0) answer = 0, tu veux que ça s'applique à tous les returns, ce qui est n'as possible si tes returns sont dispersés). Idem pour le débuggage, tu sais où mettre un point d'arrêt si tu veux savoir ce qui sort de ta fonction. n

    Le désavantage majeur, tu l'as noté, c'est quand tu as des cas où le traitement n'est pas nécessaire (if (i == 0) return 0), que tu vas devoir remplacer par un niveau d'imbrication supplémentaire.

    Je ne pense pas que ce genre de décisions de design soient prises à la légère : des développeurs expérimentés ont estimé le rapport coût/bénéfices de ce choix, éclairé par leur expérience, et ont pensé que ce rapport était avantageux. Chaque langage a ses paradigmes, if(i==0) return -1 else return i , c'est pareil que if (i==0) i = -1; return i; et une forme peut être privilégiée dans chaque langage pour tout un tas de raisons.

  • # Programmation fonctionnelle

    Posté par  (site web personnel) . Évalué à 10.

    Autant que je sache, ça vient d'habitudes de langages de programmation fonctionnelle. J'ai en tête Caml par exemple. Si je me souviens bien, l'idée est qu'il n'est pas normal de faire quoi que ce soit qui retourne une valeur sans faire quelque chose de cette valeur : l'affecter à une variable par exemple.

    Du coup, dans la définition d'une fonction, on s'attend à ce qu'aucune ligne ne laisse de valeur implicitement jetée à la poubelle. Et il devient du coup plus ou moins naturel que, lorsqu'une ligne, une seule, la dernière, laisse une valeur, ce soit la valeur de retour de la fonction.

    On peut voir les choses autrement. Une fonction est comme l'objet du même type en mathématiques : quelque chose qui prend des valeurs et fournit une valeur. Or en maths, on écrit fort naturellement (ou pas) des choses comme : f: x ↦ x². Et certainement pas f: x ↦ return x².

    • [^] # Re: Programmation fonctionnelle

      Posté par  (site web personnel) . Évalué à 7.

      À noter que cela permet autre chose d'intéressant, si le concepteur du langage y a pensé : utiliser cette notion de valeur de retour au niveau, non pas seulement de la fonction, mais plus généralement du bloc de code. Vous savez, le bloc, une portion de code entre accolades par exemple. Dans les langages où c'est défini, ça sert entre autres pour la portée des variables, mais ça permet aussi de grouper des instructions et de définir les structures de contrôle comme travaillant sur des blocs.

      Bref, en clair, cette idée de valeur de retour peut permettre des trucs comme ça :

      n = 3
      printf("Il y a %d %s", n, if n <= 1 {
          "vélo"
      } else {
          "vélos"
      })
      • [^] # Re: Programmation fonctionnelle

        Posté par  . Évalué à 2. Dernière modification le 26 janvier 2024 à 18:06.

        Je préfère la version :

        
        n = 3
        printf("Il y a %d %s", n, " velo", if n > 1 {"s"})
        
        
        
  • # Argh

    Posté par  . Évalué à -5.

    Quand je vois ça :

    scala> def pof(i: Int) : Int = { i + 1 };
    pof: (i: Int)Int

    scala> pof(1)
    res0: Int = 2

    scala> def pif(i: Int) : Int = {
    | val pouf : Int = i - 1;
    | pouf + 1
    | }
    pif: (i: Int)Int

    scala> pif(1)
    res1: Int = 1

    scala> def pouet(i: Int) : Int = {
    | if(i == 0 ){return -1}
    | i
    | }
    pouet: (i: Int)Int

    scala> pouet(0)
    res2: Int = -1

    je me souviens pourquoi j’aime Python…

    • [^] # Re: Argh

      Posté par  (site web personnel, Mastodon) . Évalué à 4.

      Il faut essayer de comprendre avant de critiquer…

      def pof(i: Int) : Int = { i + 1 };

      est juste (sauf que ton langage chéri ne permet pas d’écrire une ligne simple en une ligne, et que par défaut tu ne sais pas indiquer le typage…)

      def pof(i):
        return i + 1

      …et le return est simplement implicite, comme le fait remarquer le journal. Au passage, tu peux l’expliciter au besoin, mais dans la plupart des cas, en programmation fonctionnelle, tu n’as pas besoin de cette lourdeur syntaxique.
      L’exemple suivant illustre juste le fait que sans mention explicite, on retourne naturellement la dernière valeur…

      def pif(i: Int) : Int = {
        val pouf : Int = i - 1;
        pouf + 1
        }

      aurait pour équivalent (sans le typage) quelque chose comme

      def pif(i):
        pouf = i - 1
        return pouf + 1

      Franchement, je ne vois le plus de Python (sauf si on veut défendre à tout prix l’absence de typage explicite, du coup les évolutions récentes ne seront pas d’accord avec toi… et en Scala aussi, il y a plein de moments où on peut ne pas spécifier de typage mais les usagers du langage ne le font pas.)
      Voici l’équivalent (avec l’annotation de typage) pythonesque?

      def pif(i: int) -> int:
        pouf: int = i - 1
        return pouf + 1

      Pas de quoi fouetter un chat. Je fais donc parti des personnes qui ont jugé ton commentaire inutile, surtout qu’il n’y a pas d’argument constructif mais juste un ressenti forgé sur de l’ignorance.

      “It is seldom that liberty of any kind is lost all at once.” ― David Hume

      • [^] # Re: Argh

        Posté par  . Évalué à 1.

        (sauf que ton langage chéri ne permet pas d’écrire une ligne simple en une ligne, et que par défaut tu ne sais pas indiquer le typage…)

        Ou alors c'est parce que tu ne connais pas assez bien le langage que tu critiques?

        pof = lambda x: x+1
        ou avec les annotation de type:

        from typing import Callable
        pof: Callable[[int], int] = lambda x: x+1

        • [^] # Re: Argh

          Posté par  (site web personnel, Mastodon) . Évalué à 5.

          Dommage que tu remplaces une définition de fonction par une lambda expression, chose qui existe aussi en Scala. Je voulais rester dans l’esprit du journal et non réécrire la pensée de l’auteur

          val pof = (x: int) => x+1

          Dommage que tu n’ai pas lu jusqu’à la fin où j’évoque l’annotation de type. Et tu passes à côté de mon idée (qui était de montrer par une traduction pratiquement 1:1 qu’il n’y a pas de quoi être repoussé ou jeter aux orties avec des cas aussi simples) en rajoutant des imports (ça défend encore moins le langage.)

          “It is seldom that liberty of any kind is lost all at once.” ― David Hume

    • [^] # Re: Argh

      Posté par  (site web personnel) . Évalué à 10.

      je me souviens pourquoi j’aime Python…

      Parce que la syntaxe de Python t'est familière ? Et ce qui ne t'est pas familier te fait peur ?

  • # En Fortran

    Posté par  (site web personnel) . Évalué à 10. Dernière modification le 26 janvier 2024 à 21:44.

    En Fortran, je peux écrire :

    program essai
        implicit none
    
        print *, pouet(1)
        print *, pouet(0)
    
    contains
    
        integer function pouet(i)
            integer, intent(in) :: i
    
            pouet = 2
    
            if (i == 0) then
                pouet = -1
            else
                pouet = i
            end if
        end function
    
    end program essai
    

    La sortie se fait au niveau du end function et ça m'affiche :
    1
    -1

    On peut éventuellement mettre un return après l'instruction pouet = -1 pour sortir plus vite de la fonction.

    On peut aussi utiliser result pour indiquer quelle variable contiendra le résultat :

        integer function pouet(i) result(r)
            integer, intent(in) :: i
    
            r = 2
    
            if (i == 0) then
                r = -1
                return
            else
                r = i
            end if
        end function
    

    Attention, il ne faut pas déclarer la variable si on a indiqué le type de donnée devant function. La variable r est automatiquement de type integer comme indiqué en début de ligne.

  • # goto return cave

    Posté par  . Évalué à 6. Dernière modification le 26 janvier 2024 à 23:09.

    Je trouve que le return n’est quand même pas aussi problématique que le goto, mais c’est sûrement une question de goût, de façon de réfléchir et d’éducation. Il subsiste sûrement des aficionados du goto. Il y en avait encore il y a 15 ans en tous cas.

    Le return par contre, même s’il est effectivement beaucoup plus élégant que ce soit la dernière ligne d’une fonction qui soit implicitement la valeur retournée par la fonction, comme c’est l’usage, entre autre en Bash/shell (qui de toute manière ne sait retourner qu’un entier unique), le return permet de sortir de la fonction « avant la fin », à l’instar d’un "break" dans une boucle, et ça peut vraiment être utile, je trouve. Si par exemple on a un algorithme qui convient pour implémenter une fonction, mais que celui-ci ne fonctionne malheureusement pour une (ou quelques) valeur(s) connues, et que par ailleurs la valeur à retourner pour cette valeur d’entrée est constante, immuable, alors c’est quand même plaisant de ne pas avoir à chercher un algorithme « parfait » qui permettrait de traiter aussi cette valeur (algo qui sera probablement moins performant quand bien même il sera relativement évident…), ou bien de devoir s’appliquer à ce que le reste du code ne puisse jamais passer cette valeur à la fonction. Ça c’est pour le return en tout début de fonction. Mais c’est également très pratique en plein milieu de la fonction, bien que je n’ai pas d’exemple en tête là sur le moment.

    C’est sûr qu’en LISP on n’a pas à utiliser return, vu que la fonction « se retourne elle-même » si j’ose dire (et j’ose, c’est à ça qu’on me reconnaît !), mais LISP est quand même très particulier, une programmation purement fonctionnelle n’est quand même pas l’approche la plus intuitive qui soit, comparé à l’approche algorithmique. Et j’ai l’impression que pour le commun des codeurs c’est une approche hybride, qui associe les deux concepts (et d’autres), qui paraît la plus naturelle. Il me semble d’ailleurs avoir lu que LISP était particulièrement apprécié dans le domaine de la méta-programmation. Je ne suis pas assez compétent pour affirmer que c’est véridique/pertinent, mais de mon point de vue ça semble assez évident. Tout autant qu’à l’inverse faire de la méta-programmation avec des goto ça doit sûrement être fortement perturbant, level paradoxe spatio-temporel ! ^^

    • [^] # Re: goto return cave

      Posté par  (Mastodon) . Évalué à 8. Dernière modification le 27 janvier 2024 à 08:42.

      Il subsiste sûrement des aficionados du goto

      Oh oui ! Le goto est bcp utilisé en C en tant que gestion d'exception. J'ai la flemme de taper un exemple mais en gros tu mets à la fin de ta fonction tous les close() et autre free(), avec un label 'cleanup' par exemple. En cas de merdouille dans ta fonction, un goto cleanup et tu évites ainsi un bon paquet d'imbrications de if().

      Au final tu as un code très facile à lire/comprendre donc maintenir.

      EDIT : un bel exemple est dans le coding style du kernel

      En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

      • [^] # Re: goto return cave

        Posté par  (site web personnel) . Évalué à 6.

        Au final tu as un code très facile à lire/comprendre donc maintenir.

        Le GOTO a été décrié dès la fin des années 60 (https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf) parce qu'il rendait le code difficile à lire et comprendre.

        On peut donc en déduire que dans les cas où il rend le code plus facile à lire/comprendre/maintenir, on peut (devrait ?) l'utiliser. Toute règle a ses exceptions.

        Un GOTO est finalement juste une instruction JMP.

        • [^] # Re: goto return cave

          Posté par  . Évalué à 4.

          On peut donc en déduire que dans les cas où il rend le code plus facile à lire/comprendre/maintenir, on peut (devrait ?) l'utiliser. Toute règle a ses exceptions.

          Enfin encore faut-il que les règles aient du sens, ce qui n'est pas forcément le cas en ce qui concerne les goto :

          https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/

          • [^] # Re: goto return cave

            Posté par  . Évalué à 7.

            Le message de Linus, sur l'absence d'instruction break pour sortir prématurément d'une boucle en Pascal, me rappelle la situation de ceux qui utilisent pas mal le style impératifs en OCaml. Ils ont demandé plusieurs d'avoir cette primitive sur le bugtracker mais n'ont toujours pas eu gain de cause. Pour l'instant, il faut passer par des exceptions pour faire ça.

            Au lieu de :

            for ... do
              do_A;
              do_B;
              if cond then break;
            done

            il faut faire un truc du genre :

            try for ... do
              do_A;
              do_B;
              if cond then raise Break;
            done
            with Break -> do_check

            Bon dans le fond ça change rien, les exceptions en OCaml c'est un jump (à la manière des exceptions en C via goto), mais ça rendrait le code peut être plus clair avec un break.

            Sinon pour revenir au journal, en programmation fonctionnelle ce n'est pas forcément la dernière valeur qui est retournée. C'est juste que c'est un style orienté expression et non instruction.

            Dans le code suivant :

            let foo cond = if cond then 2 else 3

            la valeur retournée dépend du booléen est peut être 2 ou 3. Ça équivaut à ce code :

            (* return est juste la fonction identité *)
            let return x = x
            
            (* le même code qu'avant *)
            let foo cond = if cond then return 2 else return 3

            Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

            • [^] # Re: goto return cave

              Posté par  . Évalué à 4.

              Un petit bonus sur le returncomme fonction identité, les exceptions et les pointeurs. En fait, on peut bien trouver des return en OCaml, quand on quitte ce que l'on appelle la monade identité. Ce qui peut être le cas quand on travail avec des pointeurs à la places d'exceptions.

              La fonction int_of_string_opt a pour type string -> int option. Ce qui veut dire qu'elle prend une chaîne de caractères pour la convertir en int. Par contre, si c'est pas possible, au lieu de lever une exception, elle retourner l'équivalent OCaml d'un pointeur sur int (qui est le pointeur nul en cas d'échec). Et bien, on peut travailler avec ces pointeurs comme si c'était des int. Le tout c'est de lui dire comment si prendre pour travail avec un fonction qui attend un a et retourne un pointeur sur b, comment on s'y prend pour lier une valeur à une variable quand on travaille avec des pointeurs.

              let bind x f = match x with Some v -> f v | None -> None

              Si j'ai un pointeur valide je passe la valeur pointée à f, sinon je retourne toujours le pointeur nul.

              Ensuite, il faut dire comment on obtient un pointeur à partir d'un valeur donnée :

              let return x = Some x

              Enfin on peut écrire le code suivant :

              let foo s s' =
                let ios = int_of_string_opt in
                let (let*) = bind in
                let* x = ios s in
                let* y = ios s' in
                return (x + y)

              Fonction qui s'utilise ainsi :

              (* tout va bien on a un pointeur sur int *)
              foo "21" "21";;
              - : int option = Some 42
              
              (* on a un pointeur nul *)
               foo "a" "21";;
              - : int option = None

              C'est ainsi que les exceptions sont gérées en Rust via la monade d'erreurs. :-)

              Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

              • [^] # Re: goto return cave

                Posté par  . Évalué à 3.

                en programmation fonctionnelle ce n'est pas forcément la dernière valeur qui est retournée. C'est juste que c'est un style orienté expression et non instruction.

                let foo cond = if cond then 2 else 3

                Je suis pas sûr de te suivre. Une fonction par principe la (ou les) valeur(s) qu’elle retourne dépendent uniquement des valeurs d’entrée). Il est exclu que l’état d’une autre fonction ou qu’une instruction puisse changer cela.

                L’expression que tu donnes en exemple ci-dessus, tu considères qu’elle relève de l’expression ou de l’instruction ? Et "cond" est identique des deux côtés de l’égalité ?

                • [^] # Re: goto return cave

                  Posté par  . Évalué à 5.

                  foo est une fonction, cond un paramètre, on pourrait mettre des parenthèse mais c'est pas la coutume dans certains langages comme Haskell. Après le = on a la définition de la fonction.

                  Le "if" est une expression qui prend une valeur, qu'on affecte à l'évaluation de la fonction. C'est des langages qui fonctionnent comme le lambda calcul, on évalue les parties genre les appels de fonction, et à la fin de l'exécution on a plus rien à évaluer (si ça termine), et on a une valeur du programme en résultat.

                  Du coup on peut voir le "if" lui même non comme une structure de contrôle mais comme une fonction, dans un langage fonctionnel, comme dans les tableurs par exemple. En fonction du booléen en entree, on retourne (s'évalue en) la valeur du deuxième ou du troisième paramètre.

                • [^] # Re: goto return cave

                  Posté par  . Évalué à 4. Dernière modification le 28 janvier 2024 à 09:45.

                  Et le coup de l'absence de parenthèse ça met plus apparent / facile à exploiter un certain fait mathématique : on peut donner à manger une partie seulement une partie des paramètre et obtenir une autre fonction mathématique.

                  L'exemple classique c'est l'addition. On peut faire une fonction qui ajoute 5 à un nombre comme ça :

                  let ajoutecinq = add 5

                  "ajoutecinq 10" s'évalue en "15". Ça illustre une relation entre les fonctions avec plusieurs paramètres et les fonctions qui en prennent un seul et qui retourne … Une fonction qui en prendra un autre, jusqu'a l'évaluation en une valeur non fonctionnelle. On peut en fait carrément se passer de la notion de fonction à plusieurs paramètres. Et c'est ce qu'illustre l'absence de parenthèse. C'est très exactement ce qui se passe quand tu regardes le type d'une fonction en Haskell, pas de parentheses mais des flèches partout entre les "paramètres".

                  Et si tu veux quand même des parethèses, tu utilises des tuples. Les tuples sont des types (types produit dans le jargon), ils s'écrivent généralement avec des parenthèses. Tu peux donc faire une fonction qui prend les paramètres entre parenthèses… Mais qui n'a toujours qu'un seul paramètre, une valeur de type n-uplet.

                • [^] # Re: goto return cave

                  Posté par  . Évalué à 5. Dernière modification le 28 janvier 2024 à 11:03.

                  L’expression que tu donnes en exemple ci-dessus, tu considères qu’elle relève de l’expression ou de l’instruction ?

                  Thomas t'as répondu sur le reste, je ne reviendrais donc que sur cette question. Quand je dis que c'est orienté expression, c'est que l'on ne code pas en pensant au fait que cela sera traduit en instruction pour une machine (c'est le travail du compilateur de faire cela) mais que l'on a des expressions, définies les unes à partir des autres, que l'on cherche à évaluer. L'exécution du programme ne consistant qu'en l'évalutation de ces expressions.

                  La construction if true then 2 else 3 est une expression au même titre que n'importe qu'elle entier, et qui s'évalue ici à 2. Et je peux l'utiliser ainsi :

                  (if true then 2 else 3) + 1;;
                  - : int = 3

                  Lorsque l'on définit une fonction comme foo, on explique juste comment évaluer une expression à partir d'une autre donnée en paramètre. Ainsi, on a :

                  (foo true) + 1;;
                  - : int = 3
                  
                  (foo false) + 1;;
                  - : int = 4

                  Il n'y a pas besoin de return explicite, parce que le modèle de calcul veut que lorsque une fonction en appel une autre (ce qui est aussi un saut dans le code) elle retourne (encore un saut) avec la valeur de l'expression qu'elle a évaluée.

                  Après, si on veut signifier cet aller-retour entre en l'appelant et l'appelé via un return et un bind (pour décrire ce que fera l'appelant de la valeur retournée), on aboutit à la structure de monade décrite plus haut, structure qui, si on analyse son fonctionnement, mène à la notion d'effets ;-) (voir les futurs leçons de Xavier Leroy sur le sujet).

                  Dans le cas de la monade d'erreurs (les exceptions à la sauce Rust), le code du bind est le suivant :

                  let bind x f = match x with
                    | Ok v -> f v
                    | Error _ as e -> e

                  Autrement dit, sa sémantique est la propagation des exceptions : si on reçoit une valeur on la traite, sinon on retourne l'erreur reçue au code appelant supérieur, jusqu'à ce qu'il y en ait un qui la traite. ;-)

                  On aboutit alors à des notions bien mieux structurées qu'un simple goto pour gérer les sauts dans le code. ;-)

                  Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                  • [^] # Re: goto return cave

                    Posté par  . Évalué à 5.

                    L'exécution du programme ne consistant qu'en l'évalutation de ces expressions.

                    Je vois bien l’idée mais ce contraindre à coder uniquement selon ce paradigme me semble relever de la manie pathologique.

                    Obsession qui s’opposerait celle qui consisterait à assumer systématiquement que tout usage du goto est légitime et pertinente ^

                    Je note la notion d’« effet » dans un coin de ma tête… mais là j’ai prévu de me pencher à nouveau sur un autre langage que j’avais abordé il y longtemps et auquel j’ai envie de m’intéresser à nouveau.

                    J’ai le sentiment qu’un return (qui existe en Lisp), est compatible avec un paradigme fonctionnel strict (ce n’est pas un saut vers « n’importe où », juste un raccourci dans la fonction…), alors que le goto (qui peut lui sauter vers n’importe où) ne l’est pas (du moins pas sans convolutions extrêmement coûteuses, et donc inenvisageables)

                    • [^] # Re: goto return cave

                      Posté par  . Évalué à 5. Dernière modification le 29 janvier 2024 à 23:54.

                      Je vois bien l’idée mais ce contraindre à coder uniquement selon ce paradigme me semble relever de la manie pathologique.

                      Je ne vois pas bien ce qu'il y a de pathologique là-dedans. C'est un paradigme comme un autre, celui suivi par tous les langages fonctionnels du LISP jusqu'à nos jours, langages qui ont tous pour modèle le lambda-calcul d'Alonzo Church. Church était le directeur de thèse de Turing, et le seul intérêt que je vois à son modèle de calcul sur machine est que l'on peut compiler en une suite d'instruction machine un code écrit en lambda-calcul (les deux modèles sont équivalents). Procéder par évaluation d'expression, c'est ce que je fais depuis que j'ai appris à calculer à l'école primaire avec un papier et un crayon. Je ne vois pas bien le côté pathologique a toujours faire de même. ;-)

                      J’ai le sentiment qu’un return (qui existe en Lisp), est compatible avec un paradigme fonctionnel strict

                      LISP (qui est orienté expression) a aussi des traits impératifs (c'est du fonctionnel impur) et le return permet, entre autre, de sortir prématurément d'une boucle (cf. mon commentaire sur le message de Linus). Dans un langage fonctionnel pur, toute boucle est une fonction récursive et si l'on veut sortir, il suffit de ne pas relancer la récursion et de dire à quelle expression s'évalue le retour de fonction (le return explicite devient purement facultatif).

                      Ce qui me semble pathologique, c'est ce besoin irrépressible d'avoir un return quelque part dans le corps d'une fonction. ;-)

                      Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                      • [^] # Re: goto return cave

                        Posté par  . Évalué à 3.

                        LISP fonctionnel impur ? Quel langage est le plus « pur » parmi les langage fonctionnels ? Lisp me semblait être celui faisant le moins de concession mais je me trompe probablement. OCaml ? Un autre ?

                        Le Haskell avait l’air plutôt attirant mais je n’ai jamais trouvé le temps et la motivation de m’y mettre sérieusement. Selon toi c’est un langage encore plus orienté langage fonctionnel que peut l’être LISP/Common Lisp ?

                        • [^] # Re: goto return cave

                          Posté par  . Évalué à 2.

                          Haskell et Elm (qui est fortement inspiré du premier) dans ce que je connais. Le O d'Ocaml est pour objective, il est multi paradigmes et c'est ça raison d'être.

                          Elm est peut-être moins rugueux qu'haskell et sert à créer des sites comme angular, react ou vue,mais avec une architecture différente. Par contre il est loin d'être aussi sophistiqué qu'haskell.

                          https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

                        • [^] # Re: goto return cave

                          Posté par  . Évalué à 4. Dernière modification le 30 janvier 2024 à 00:42.

                          Quel langage est le plus « pur » parmi les langage fonctionnels ?

                          Tu le cites juste après c'est Haskell. ;-) Il y a des traits impératifs dans tous les autres (si on oublie ceux à types dépendants), OCaml y compris. Tu ne peux pas faire d'entrée-sortie en Haskell sans passer par le monade IO, toutes les valeurs sont immuables, aucun effet de bords…

                          En parlant de monade et de ton return LISP qui ne va pas n'importe où : oui il saute à l'entrée où le code de la fonction avait été appelé, mais sans son double correspondant, le bind, c'est une structure de contrôle qui ne vaut pas grand chose.

                          Ce qui me semble pathologique, par exemple, c'est la gestion des erreurs en go où l'on voit répéter à longueur de code le même pattern:

                          if err != nil {
                            do_this;
                            do_that;
                          }

                          Voilà ce que fait une code appelant du retour qu'il reçoit après un calcul qui peut échouer : c'est son bind. ;-)

                          Quand tout est expression, ce motif est aussi une expression, qui peut alors devenir paramètre formel d'une autre expression, d'où le bind de la monade d'erreur :

                          let bind x f = match x with
                            | Ok v -> f v
                            | Error _ as e -> e

                          On l'écrit une bonne fois pour toute et il n'est plus nécessaire de le recopier des centaines de fois à longueur de code, ce qui relève de la pathologie malsaine. ;-)

                          On peut alors, dans son code, se concentrer sur la partie importante : que faire du résultat quand on en a un ? On n'attrape alors qu'en toute fin de fonction les erreurs que l'on veut attraper si l'on souhaite en gérer certaines au lieu de disséminer cela dans tous les sens dans le corps de la fonction. ;-)

                          En résumé : les programmeurs go utilise le bind de la monade identité quand il travaille dans la monade d'erreurs, ce qui rend leur code de gestion d'erreurs totalement imbitable dès qu'il y en a plusieurs qui s'enchainent.

                          Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                          • [^] # Re: goto return cave

                            Posté par  . Évalué à 4.

                            Pour expliciter ça, si j’ai bien compris, j’aime beaucoup le présentation, en F#, suivante.

                            • [^] # Re: goto return cave

                              Posté par  . Évalué à 3. Dernière modification le 30 janvier 2024 à 17:39.

                              Oui l'image du trains, des rails et des aiguillages et une bonne image pour présenter le fonctionnement d'une monade. Ce qui est décrit est valide quelque soit la monade choisie et pas seulement celle d'erreurs : c'est une question de composition de diagonale dans les calculs.

                                        f                 g
                               A   ----------->  B   ----------->  C
                               |                 |                 |
                               |                 |                 |
                               V      map f      V       map g     V
                              F(A) -----------> F(B) -----------> F(C)
                              

                              Ici A, B et C sont des types et F est un types paramétriques. Le but d'une monade est de composé les diagonales : aller de A à F(C) en prenant les chemins A -> F (B) et B -> F(C). Ce qui dans le cas des erreurs correspond à un calcul produisant peut être un B à partir d'un A et un autre produisant peut-être un C à partir d'un B. En composant ces deux fonctions, on en obtient une qui produit peut être un C à partir d'un A.

                              Dans le cas de la monade identité, on a F(A) = A, les deux lignes du haut et du bas sont les même et c'est le principe du pipe du shell : on pipe A dans f puis le résultat dans g et on obtient C. Une monade c'est juste une généralisation du principe du pipe du shell.

                              Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                              • [^] # Re: goto return cave

                                Posté par  . Évalué à 5.

                                Il y a aussi une présentation sur cette page qui est mieux que mon lien précédent.
                                J’aime beaucoup cette présentation, et je la montre dès que je peux pour la faire découvrir à des collègues.

                      • [^] # Re: goto return cave

                        Posté par  . Évalué à 5.

                        Je ne vois pas bien ce qu'il y a de pathologique là-dedans. C'est un paradigme comme un autre, celui suivi par tous les langages fonctionnels du LISP jusqu'à nos jours, langages qui ont tous pour modèle le lambda-calcul d'Alonzo Church.

                        En fait c'est le même problème que je rencontre un peu régulièrement dans ma carrière: l'absolutisme des dogmes.

                        • Attends faut tout décomposer en unité fonctionnelle, résultat : un paquet de classe n'ayant qu'une seule fonction, des plats de spaghetti a tout va…
                        • Attends faut faire des interfaces pour toutes les classe; résultat un paquet d'interface vide étendant une autre, et une seul implémentation qui s'appelle InterfaceImpl; petit indice si votre implémentation d'interface est juste InterfaceImpl, faut revoir la copie
                        • Attends faut faire des micro-service : résultat des échange permanent entre certain service qui sont intimement liés et qui foutent le border lors de certaines interaction pour la gestion des cas d'erreur
                        • Attends faut coder générique : Résultat un code illisible; note bien l’absence de généricité pose aussi problème quand faut corriger 5 ou 6 fois le même problème.

                        Je ne dit pas que tout ce qui est au dessus est mal, mais avoir un peu de souplesse lorsqu'on applique les dogmes ou paradigmes peut largement simplifier le code, la maintenance et la lisibilité. Mais attention a pas tomber dans l'excès et changer de paradigme & de méthode tout le temps; il faut trouver un juste équilibre.

                        Et la… Toute la question est là. Il y a de bons développeur qui…

                        nan j'déconne y'en a pas :P

                        Bref lorsqu'on énonce des principes de codage/programmation, il faut en expliquer la raison et le gain, pour permettre au développer (ou architecte) de déroger à ces principes si le besoin s'en fait sentir, les appliquer bêtement et aveuglement finit fatalement par des usine à gaz.

                        Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                        • [^] # Re: goto return cave

                          Posté par  . Évalué à 2.

                          En fait c'est le même problème que je rencontre un peu régulièrement dans ma carrière: l'absolutisme des dogmes.

                          Ce n'est pas une question de dogmes mais de modèle de calcul : lambda-calcul ou machine de Turing. Ce que tu décris ensuite relève de principes architecturaux d'organisation de codes, et n'a rien à voir avec le modèle de calcul sous-jacent aux langages. On peut les appliquer correctement, ou n'importe comment sans rien y comprendre, et cela quelque soit le modèle de calcul choisi par le langage sous-jacent dans lequel on implémente nos idées.

                          Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                • [^] # Re: goto return cave

                  Posté par  . Évalué à 4. Dernière modification le 28 janvier 2024 à 22:20.

                  Une analogie qui m'est revenue, sur le style orienté expression, est celle des phrases à trous. Une fonction Ocaml (ou dans le style fonctionnel) c'est comme les phrases à trous. Dans la fonction foo cond = if cond then 2 else 3, c'est juste une expression if _ then 2 else 3 qui comporte un trou, trou auquel le paramètre formel donne un nom. Appeler la fonction consistant à dire quoi mettre dans le trou pour former une expression.

                  En français, on pourrait écrire « la première fonction Scala définie par martoni dans son journal ». Cette phrase désigne ("s'évalue") la fonction pof. On peut, ensuite, mettre un trou à la place de « première »; on a alors la phrase à trou « la ____ fonction Scala définie par martoni dans son journal ». Ou, si l'on nomme le trou : « la nième fonction Scala définie par martoni dans son journal ». Cette dernière phrase est une fonction qui prend un entier en paramètre (pour combler le trou) et retourne le nom d'une fonction :

                  • 1 -> pof
                  • 2 -> pif
                  • 3 -> pouet

                  C'est ça le style expression : on écrit des phrases à trous au lieu d'un suite d'instructions données à la machine (c'est le rôle du compilateur de passer d'un style à l'autre). Le return (des langages impératifs) étant vu, de base, comme une instruction pour la machine.

                  Il va de soi que la phrase à trou « Tu bluffes ___ ! » n'accepte que martoni en paramètre. :-P

                  Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

        • [^] # Re: goto return cave

          Posté par  (Mastodon) . Évalué à 8. Dernière modification le 27 janvier 2024 à 10:49.

          Le GOTO a été décrié dès la fin des années 60

          Comme beaucoup à mon époque (fin des 80's) j'ai commencé en BASIC avec numéro de lignes. Le GOTO était pour ainsi dire la seule instruction de contrôle de flot. IF et GOTO partout, pas de WHILE ni de FOR.

          Le code était vraiment compliqué à comprendre à posteriori, et les effets de bords très courants. Mais le soucis c'est que quand tu es habitué à coder comme ça, c'est très dur de t'adapter à autre chose, et l'effort est important pour changer. Je suppose que la malédiction du GOTO vient de l'époque où on a cherché à faire basculer tout le monde.

          Maintenant le GOTO utilisé à bon escient et avec parcimonie reste un outil simple et efficace.

          dans les cas où il rend le code plus facile à lire/comprendre/maintenir, on peut (devrait ?) l'utiliser

          En général il est utilisé comme moins pire que :
          - trop de if() imbriqués pour vérifier des codes de retour successifs
          - trop de return() un peu partout dans la fonction

          Chacun mettra "trop" à ses propres valeurs :)

          Un GOTO est finalement juste une instruction JMP.

          Et oui. On sait bien que for() et while() sont traduits en assembleur en IF et JMP (souvent dans la même instruction tellement c'est courant).

          En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

          • [^] # Re: goto return cave

            Posté par  (site web personnel) . Évalué à 8.

            Mais le soucis c'est que quand tu es habitué à coder comme ça, c'est très dur de t'adapter à autre chose, et l'effort est important pour changer. Je suppose que la malédiction du GOTO vient de l'époque où on a cherché à faire basculer tout le monde.

            Il y a peut-être un effet lié à l'âge, ceux qui programmaient depuis 20 ou 30 ans avec des GOTO ont pu avoir du mal à changer de façon de faire.

            J'ai appris la programmation avec le BASIC du début des années 80 de type Microsoft, avec les numéros de ligne obligatoires. A l'époque, apprendre l'assembleur n'était pas très compliqué, c'était juste plus basique que le BASIC… Les microprocesseurs 8 bits étaient simples, le système était en ROM, etc. Et passer du GOTO au JUMP/JMP se faisait naturellement.

            J'ai appris la programmation structurée avec Turbo Pascal et le GFA Basic (Atari ST). Je ne me souviens pas d'avoir trop peiné, mais le cerveau était encore jeune et malléable. :-)

            • [^] # Re: goto return cave

              Posté par  . Évalué à 5. Dernière modification le 27 janvier 2024 à 14:28.

              Sinon, pour l'évolution des pratiques en la matière, il y a le cours de cette année de Xavier Leroy au Collège de France Structures de contrôle : de « goto » aux effets algébriques.

              Cette fois, les effets algébriques sont des exceptions sous stéroïdes et c'est un peu plus qu'un simple jump. Depuis leur arrivée dans OCaml 5 (avec le multicore), il y a une émulation et une concurrence qui se crée pour implémenter des ordonnanceurs en utilisant les effets.

              Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

              • [^] # Re: goto return cave

                Posté par  (site web personnel) . Évalué à 4. Dernière modification le 27 janvier 2024 à 16:40.

                Ca a l'air de haute volée…

                J'ai trouvé cette page : https://xavierleroy.org/courses/JFLA-2023/index.html

                La première partie de ce cours illustrera la pratique des effets en OCaml 5. On peut les voir comme une généralisation des exceptions: lever un effet interrompt le calcul en cours, tout comme lever une exception; mais au contraire des exceptions, le calcul en cours peut être redémarré plus tard. C'est le gestionnaire de l'effet qui décide quand et avec quelle valeur redémarrer ce calcul.

                Ca me fait un peu penser à une interruption matérielle…

                • [^] # Re: goto return cave

                  Posté par  . Évalué à 5.

                  J’avais un peu regardé et de ce que j’ai cru comprendre c’est un peu l’inverse, une interruption matérielle c’est imposé au processus. Ce serait le matos qui dit au processus "j’ai une IO, démerde toi avec" quel que soit l’état du processus à ce moment là.

                  Là ce serait plutôt "j’ai besoin d’une io, démerde toi pour me filer un entier", sans préciser du tout si ça vient du clavier (genre implémentation de l’inversion des dépendance) et c’est le gestionnaire d’effet installé qui va s’occuper de récupérer un entier. Une fois fini le gestionnaire d’effet refile un entier et le calcul reprend.

                  • [^] # Re: goto return cave

                    Posté par  . Évalué à 3. Dernière modification le 27 janvier 2024 à 22:32.

                    C'est une bonne manière de présenter la chose. On est proche de l'usage du goto dans le dernier message de Robert Love dans l'échange sur la mailing list du kernel postée plus haut, où l'usage est qualifié de cleanly do the usual stack-esque wind and unwind. Mais ici chaque code d'un appelé via goto peut retourner à l'appelant via un goto pour reprendre l'éxecution. Et là, on arrive au code spaghetti si c'est fait à coup de goto et non de primitives plus structurées. ;-)

                    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                    • [^] # Re: goto return cave

                      Posté par  (site web personnel) . Évalué à 4.

                      Mais ici chaque code d'un appelé via goto peut retourner à l'appelant via un goto pour reprendre l'éxecution.

                      Toute convention de langage un minimum bien pensé autorisant le goto en C ne l'autorise que pour descendre dans le code et non remonter dans le flux d'exécution pour éviter ça comme des erreurs plus gênantes.

                      • [^] # Re: goto return cave

                        Posté par  . Évalué à 3. Dernière modification le 27 janvier 2024 à 23:23.

                        Oui, et c'est une application du goto statement considered harmful. Mais dans le fond, il est trop conservateur : pour éviter toute erreur, on interdit par convention certains usages. Sauf que l'usage que je décris est celui des effets mais, s'il est fourni par des primitives mieux structurées que goto, alors il est tout de suite moins harmful et bien pratique.

                        Celui que décrit Robert Love dans son message est celui des exceptions, celui que je décris est celui des effets. ;-)

                        Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                        • [^] # Re: goto return cave

                          Posté par  . Évalué à 3.

                          Celui que décrit Robert Love dans son message est celui des exceptions, celui que je décris est celui des effets. ;-)

                          Je pense qu'il y a méprise. Goto considered harmful ne dit pas qu'il ne faut pas de saut dans le code, il dit que toutes construction de plus haut niveau sera plus lisible, moins source de bug et évitera d'avoir à mettre des labels partout dans le code.

                          La gestion des ressources tu as des constructions qui sont bien moins sujettes aux bugs (dont le document des développeurs du noyau parle lui-même) avec defer, la RAII, les try-with-ressource,…

                          Pour les effets tu décris une construction de plus haut niveau qui a plus de sémantique à la lecture.

                          Dijkstra dis simplement que goto est trop primitif, pas qu'il ne permet pas de construire des structures de contrôles intéressantes. Mais ces structures seront toujours auront toujours plus de valeur si elles sont codifiée dans leur propre structure y apportant un nom, une sémantique claire etc

                          https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

                      • [^] # Re: goto return cave

                        Posté par  (site web personnel) . Évalué à 2.

                        C'est amusant ce que tu dis, j'ai tout de suite vu ça en comparant avec les voyages dans le temps !

            • [^] # Re: goto return cave

              Posté par  (site web personnel, Mastodon) . Évalué à 4.

              Après quand ton code est bien « structuré » ça ne pose pas de réel problème d’utiliser du GOTO ou pas ; ce qui est décrié c’est l’usage désordonné (le fameux code spaghetti) mais il est plus facile de pointer du doigt et ériger des dogmes que de comprendre la problématique.

              “It is seldom that liberty of any kind is lost all at once.” ― David Hume

              • [^] # Re: goto return cave

                Posté par  . Évalué à 1.

                L'outil n'est pas neutre. Tu peux tailler tes courgettes avec un karambit, mais il existe des couteaux avec les quels tu as moins de chances de perdre un doigt. Pourtant il est tout à fait possible de cuisiner proprement avec.

                Le cas que tout le monde cite c'est la gestion de ressources. Hé ben quand tu as le choix tu utilisera defer ou de la RAII, qui sont moins casse gueule.

                https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

      • [^] # Re: goto return cave

        Posté par  . Évalué à 3.

        C’est pas possible d’implémenter un try … catch … en C ?

        Ceci dit si le goto fait le job et qu’il n’est pas par ailleurs utilisé pour faire n’importe quoi dans le reste du code ça semble effectivement totalement inutile de chercher à le remplacer.

        Je connais pas assez le C (et ma méta-expertise a ses limites) pour avoir un avis un tant soit peu pertinent, mais j’aurais tendance à dire que le goto, à l’instar de tout outil/technique/méthode qui présente une utilité certaine pour résoudre des problèmes particuliers, quand bien même il peut également être une source avéré de monstruosités confondantes quand il est mal utilisé, n’a strictement aucune raison de devoir être poussé vers la sortie.

        • [^] # Re: goto return cave

          Posté par  . Évalué à 6.

          C’est pas possible d’implémenter un try … catch … en C ?

          En théorie oui, mais en pratique cela me semble de peu d'utilité. Le C est un langage normé ISO, processus long et complexe, et il faudrait ajouter un garde-fou sans grande utilité pratique : ceux qui utilisent le goto pour cela savent très bien s'y prendre, et il est impossible de retirer le goto pour des raisons de compatibilité historiques avec le code existant. À quoi bon rentrer dans un processus de normalisation ISO sans intérêt pratique ?

          Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

          • [^] # Re: goto return cave

            Posté par  . Évalué à 3.

            Je ne pensais pas à modifier le langage pour y ajouter un try … catch … mais d’avoir une construction native en C qui fasse le job. Mais manifestement c’est peut-être précisément ça que font les programmeurs C avec le goto ^^

            • [^] # Re: goto return cave

              Posté par  (site web personnel) . Évalué à 6.

              L'autre solution, c'est avec des longjmp/setjmp:
              http://groups.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
              Par contre, c'est lent, et une énorme source du bug.
              En fait ce sont surement les fonctions les plus dangereuses de C, et c'est presque tout le temps une mauvaise idée de les utiliser.
              Comparer aux exceptions C++, un longjmp ne va pas appelle les free fait entre le setjmp et le longjmp, de plus laisse ton programme dans un état qui est beaucoup plus dur à contrôler, qui si le flow du programme est linaire.
              Dalleur, que ça soit le mécanisme de defer ou __attribute__(cleanup) le comportement est indéfini, si un longjmp est fait après le defer/cleanup.

              • [^] # Re: goto return cave

                Posté par  . Évalué à 4.

                En C tu n’essayes pas. Tu es sûr de toi ou tu ne fais pas ! :) (et tu ramasses tes données en mémoire et tu libères la place, merci)

          • [^] # Re: goto return cave

            Posté par  . Évalué à 1.

            ceux qui utilisent le goto pour cela savent très bien s'y prendre

            Avec ce genre d'arguments il n'y a plus d'overflow. Personne ne découvre le langage, personne ne commet de faute etc

            Je ne dis pas ce qu'ils doivent faire ni que le C doit changer (d'autres se lancent dans l'aventure), juste que l'argument me semble faible et ça a l'air d'être un sujet puisque des compilateurs comme gcc et clang ont ces extensions. Il doit y avoir des développeurs C qui pensent pas qu'il y a de la valeur à avoir une construction de plus haut niveau.

            https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

            • [^] # Re: goto return cave

              Posté par  (site web personnel) . Évalué à 3.

              Ceci dit il me semble que kantien parle de remplacer les goto, par des try/catch.
              Les extensions dont tu parles servent à faire soit un genre de RAII, soie des defer.
              Le seul compilateur C qui gère try/catch, c'est MSVC.

              Personnellement, j'aime beaucoup les mécanismes de defer, et autres, car ça permet de gérer la libération des ressources, au moment où on les crée, et donc moins de chances d'oublier.
              Le problème des goto out; c'est qu'on a le label out à la fin de la fonction, et c'est facile d'oublier de rajouter le free.
              Avec les try/catch, le problème reste assez similaire aux goto.

              C'est moi qui avais push la 1ʳᵉ version de attribute cleanup dans tinycc, (qui était pas mal bugué, les mainteneurs ont quand même pas mal amélioré mon code). Je n'aurais clairement pas fait le même effort pour imiter les try/catch de MSVC.

            • [^] # Re: goto return cave

              Posté par  . Évalué à 5.

              Avec ce genre d'arguments il n'y a plus d'overflow. Personne ne découvre le langage, personne ne commet de faute etc

              Uso a raison sur ce que je voulais dire. L'usage du goto en C est tout à fait anodin et n'est pas comparable à la gestion mémoire. C'est limité à la portée de la fonction et permet simplement une meilleure organisation et lisibilité du code. C'est du même ordre que l'usage des exceptions locales en OCaml (exception dont la définition est interne à une fonction) qui sont toutes rattrapées et n'ont aucune chance de se propager n'importe où.

              Ce qui est risqué c'est l'oubli de mettre un bout de code ou un mauvais code dans chaque label, mais ça un système de try ... catch ne le résoudra pas non plus.

              Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

    • [^] # Re: goto return cave

      Posté par  (site web personnel, Mastodon) . Évalué à 4. Dernière modification le 27 janvier 2024 à 15:50.

      L’appellation fonction est un un abus de langage pour les shell traditionnels Unix, mais c’est un autre débat. En tout cas, ce qui est retourné est un code de retour/erreur…

      Le paradigme fonctionnel ne s’oppose pas à l’approche algorithmique, et on peut implémenter tout algorithme (cf. discussions sur une autre dépêche sur la question de l’algorithmie) dans un langage fonctionnel. ;) D’ailleurs ces langages permettent d’écrire des solutions plus naturellement…

      “It is seldom that liberty of any kind is lost all at once.” ― David Hume

  • # GOTO cachés...

    Posté par  (site web personnel) . Évalué à 6. Dernière modification le 27 janvier 2024 à 13:18.

    Dans les versions modernes du Fortran, le GOTO est toujours disponible même si on ne s'en sert plus en général.

    Mais il en reste des versions cachées. Par exemple, voici un bout de code disponible dans la norme Fortran 2018 (j'ai juste changé la valeur de err) :

        read (nunit, (3f10.3), iostat=ios, err=666, end=120) a,b,c 
        ! Successful read - continue execution. 
        ... 
        666 call error (ios) ! Error condition - take appropriate action. 
        return 
        120 call last_file ! End of file - test for more files.

    Comme il n'y a pas de gestion d'exceptions en Fortran, on voit qu'on gère les erreurs d'entrées/sorties avec un label numérique. On peut aussi le faire pour la détection de la fin du fichier. C'est un peu surprenant dans un code moderne où il n'y a autrement plus aucune raison d'utiliser des labels numériques.

  • # Également dans Nim

    Posté par  . Évalué à 3.

    Nim possède le « return » implicite, mais il est toujours possible de l'utiliser pour les sorties rapides en dehors du cheminement attendu.
    Il y a également un troisième larron: « result », mais cela semble déconseillé.

    https://status-im.github.io/nim-style-guide/language.result.html

    Discussions en français sur la création de jeux videos : IRC freenode / #gamedev-fr

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.