Fonctions et procédures

Edit : Ajout d'une autre possibilité suite à une remarque d'Alexis.

Je crée dans WinDev® des procédures depuis des années. Avec le temps, on peut dire que je suis devenu un pro de la procédure. Vous avez peut-être lu mes articles, je jongle avec les procédures globales, les procédures locales, les procédures internes et les procédures compilées dynamique.

Mais il y a quelque chose sur lequel je n'ai jamais trouvé de solution qui me conviennent, c'est lorsque ma procédure doit renvoyer plusieurs valeurs. Voyons les différentes méthodes et pourquoi je ne ne suis pas satisfait. Et peut-être vous trouvez vous dans le même cas ?

Pourquoi renvoyer plusieurs valeurs ?

C'est une question fondamentale. Dans l'idéal, vos fonctions ne devraient renvoyer qu'une seule valeur. Une addition renvoie une valeur, une multiplication aussi.

Bien que chaque cas soit particulier, la plupart du temps, c'est pour gérer les erreurs. Le plus souvent, on définit une valeur qui symbolise l'erreur. Par exemple, lorsqu'on ouvre un fichier, on attend un identifiant numérique, on renvoie -1 lorsqu'on ne peut pas l'ouvrir. Cette méthodologie fonctionne dans certains cas, mais si j'ai une fonction diviser, cette méthode ne permet pas d'exprimer l'erreur provoquée lors d'une division par zéro.

On peut bien entendu gérer les erreurs par un traitement dédié, mais il est souvent lourd à mettre en place, et on préfère trouver un contournement avec une valeur. Dans un prochain article, j'aborderai la gestion des erreurs, mais pour le moment, on passe par des valeurs de retours multiples.

Il y a d'autres cas où l'on doit renvoyer plusieurs valeurs de retour. Je n'ai pas d'exemple précis, je vous laisse donc les trouver.

Comment renvoyer plusieurs valeurs ?

Il y a plusieurs méthodes. Je vais les énumérer de la plus sale à la plus propre, avec leur avantages et inconvénients.

La variable globale

On définit une ou plusieurs variables globales et on les affecte lorsqu'on utilise la fonction. Pour moi, c'est une méthode interdite pour plusieurs raisons :

  • je ne vois pas la déclaration de ces variables ;
  • je ne sais pas comment sont utilisées ces variables alors qu'elles sont dans le code de ma fonction ;
  • elles sont affectées par chaque appel de la fonction, et s'il y a plusieurs appels imbriqués, on court à la catastrophe.

On oublie !

Le paramètre passé par référence

J'utilise les paramètres passés par référence dans certains cas, je ne serai donc pas violent. Mais dans la mesure du possible, j'évite de passer de tels paramètres.

Les raisons sont les suivantes :

  • l'utilisation n'est pas intuitive ;
  • le fait que ce soit une variable de retour n'est pas très explicite et oblige à mettre un commentaire ;
  • quelqu'un qui n'a pas lu le commentaire ne comprendra pas pourquoi une des variables qu'il utilise change de valeur.

La structure

C'est une méthode beaucoup plus lisible que les précédentes, mais elle présente quand même des petits défauts :

  • c'est lourd à mettre en place, il faut définir la fonction et la structure qui va avec ;
  • ça augmente les dépendances car la structure doit être déclarée quelque part et ce quelque part doit être accessible partout où l'on utilise la fonction ;
  • dans certains cas, les différentes valeurs n'ont rien à voir l'une et l'autre, et donc, leur présence dans la même structure n'est pas intuitive.

Le variant

Suite à une remarque d'Alexis dans les commentaires, on peut aussi utiliser les variants comme valeur de retour. Le fonctionnement sera très proche des structures, mais contrairement à celles-ci, il n'y a pas de définition à mettre en place et il n'y a aucune dépendance. L'utilisation est donc plus facile.

Je vous le déconseille toutefois pour les raisons suivantes :

  • Comme le dit Alexis, c'est opaque donc illisible. L’auto-complétion est impossible sur un variant. Il faut donc aller lire la documentation pour connaître sa structure.
  • Vous êtes limités dans le type des données transmises. En effet, vous ne pouvez pas renvoyer d'objets, ni de procédures, ni de tableau, ni n'importe quel élément qui subit une conversion lorsqu'on l'affecte à un variant.

La solution ?

Depuis WinDev 19, on peut utiliser la syntaxe permettant de renvoyer plusieurs valeurs de retours. La documentation de Renvoyer explique tout cela en détail.

Voici un petit exemple qui vous permettra de tester cette superbe fonctionnalité :

PROCEDURE Test(pNombre est entier)
RENVOYER (pNombre, NombreEnLettres(pNombre))

Et le test qui permet d'utiliser la fonction :

var1 est un entier
var_un est une chaîne

(var1, var_un) = Test(1)

soit (var2, var_deux) = Test(2)

Trace(var1, var_un, var2, var_deux)

Trace(Test(3))
Trace(Test(4), Test(5))

stStructure est une Structure
    UnEntier est un entier
    UneChaine est une chaîne
FIN

var6_six est une stStructure

AVEC var6_six
    (.UnEntier, .UneCHaine) = Test(6)
FIN

Trace(var6_six.UnEntier, var6_six.UneChaine)

Var7 est un entier
Var7 = Test(7)
Trace(Var7)

Var_huit est une chaîne
(,Var_huit) = Test(8)
Trace(Var_huit)

soit (, var_neuf) = Test(9)
Trace(var_neuf)
soit (var10) = Test(10)
Trace(var10)

Voici quelques explications pour chaque valeur :
1. on initialise deux variable ;
2. on peut utiliser le mot clé Soit pour définir et initialiser les deux variables ;
3. on peut directement utiliser le résultat de la fonction dans une autre procédure, dans le cas présent, les 2 premiers paramètres de la procédure Trace sont initialisés ;
4. idem que pour le 3, mais on peut utiliser plusieurs fonctions à retours multiples.
5. idem que 4 ;
6. on ne peut pas initialiser une structure, mais on peut contourner la question en passant les membres de la structure ;
7. on peut récupérer la première valeur de retour ;
8. on peut récupérer la deuxième valeur de retour ;
9. avec le mot clé Soit, on peut définir et initialiser une variable avec la première valeur de retour ;
10. idem que 9 mais pour la seconde valeur.

Et voilà, vous savez beaucoup de choses à propos de cette fonctionnalité très puissante mais très méconnue de WinDev. Il ne vous reste plus qu'à imaginer dans quel cas vous pouvez l'utiliser.

Résumé du billet

Nous avons vu dans ce billet les différentes méthodes pour renvoyer plusieurs valeurs de retour dans une fonction. Il est possible de le faire avec des variables globales, des paramètres passés par référence et des structures.

Nous avons aussi vu qu'il était possible d'utiliser la fonctionnalité des valeurs de retour multiples présent depuis la version 19 de WinDev.

Conclusion

J'espère que cet article vous a plus. Je pense qu'il me servira prochainement dans d'autres articles, en particulier celui sur la gestion des erreurs dans votre code.

N'oubliez pas que vous pouvez vous abonner à ma lettre d'information..

Je vous remercie pour votre lecture et je vous souhaite une bonne journée !

Jonathan Laurent

Read more posts about this author.

Comments