Les procédures internes introduites dans le WLangage en version 20 ont permis de simplifier grandement l'écriture de traitements, en évitant d'avoir systématiquement recours à une procédure locale.

 

Voici un exemple concret. Historiquement, lorsqu'un traitement avait besoin d'une call-back, on devait nécessairement ajouter une procédure locale à la fenêtre. Prenons pour cette illustration un menu contextuel d'une application qui affiche les précédents documents ouverts :

 

 

Avec ce code, pour que la sélection d'une option ajoutée dynamiquement au menu par la fonction MenuAjouteOption fasse l'ouverture, il faut une procédure locale :

 



Grâce aux procédures internes, la procédure locale n'est plus la seule possibilité. Elle restera avantageuse pour des traitements conséquents. Mais comme ici ou l'action est réduite, il est bien plus lisible de supprimer la procédure locale, et d'ajouter la procédure interne au niveau du code qui l'utilise :


A partir de la version 25, le WLangage permet d'utiliser une lambda ("lambda fonction") qui est une écriture plus concise des procédures internes. Dans cet exemple, le traitement est encore raccourci, la procédure interne disparaît !


En terme d'exécution le résultat sera identique. Le choix sera surtout en lien avec les habitudes de programmation de chaque développeur, car là il y en a vraiment pour tous les goûts !

Pour une concision totale, Filter, Map et Agrège sont également disponibles. L'écriture d'opérations sur les tableaux est réduite à sa plus simple expression. Voici un exemple de code autonome à copier/coller dans un bouton pour apréhender ces syntaxes. Le code est majoritairement constitué de traces explicatives, les opérations étant toutes sur une seule ligne !

 

// Soit tab1 & tab2 deux tableaux d'entiers ...
tab1 est un tableau d'entiers = [1, 2, 3, 4, 5]
tab2 est un tableau d'entiers = [3, 5]

// Et tab3 un tableau de résultat ...
tab3 est un tableau d'entiers


// Obtenir dans le tableau tab3 les éléments de tab1 qui ne sont pas dans tab2
// Autrement dit, tab3 = tab1 - tab2
tab3 = tab1.Filter(x => (TableauCherche(tab2,tcLinéaire,x) = -1 ) )

Trace("Tableau tab3 les éléments de tab1 qui ne sont pas dans tab2...")
Trace("tab1 "+TableauVersChaîne(tab1, ", "))
Trace("tab2 - "+TableauVersChaîne(tab2, ", "))
Trace("tab3 = "+TableauVersChaîne(tab3, ", "))


// Extraire les nombres impairs d'un tableau
tab1 = [1, 2, 3, 4, 5, 6, 7, 8 , 9, 10]
tab3 = tab1.Filter( x => EstImpair(x))
Trace(RC+RC+"Tableau tab3 contient les nombres impairs du tableau tab1...")
Trace("tab1 "+TableauVersChaîne(tab1, ", "))
Trace("tab3 = "+TableauVersChaîne(tab3, ", "))


// Extraire et additionner
nTotal est un entier = tab1.Filter( x => EstImpair(x)).Agrège( (valeur, masomme) => {RENVOYER valeur + masomme}, 0)
Trace(RC+RC+"Somme des nombres impairs du tableau tab1 ...")
Trace("tab1 " + TableauVersChaîne(tab1, ", "))
Trace("Somme = " + nTotal)

// Conversion Celsius Fahrenheit
tabCelcius est un tableau de réels = [36.5, 37, 37.5, 38, 39]
tabFahrenheit est un tableau de réels
tabFahrenheit = Map(tabCelcius, CelciusToFahrenheit)
Trace(RC+RC+"Conversion Celsius Fahrenheit ...")
Trace("tabCelcius " + TableauVersChaîne(tabCelcius, ", "))
Trace("tabFahrenheit " + TableauVersChaîne(tabFahrenheit, ", "))


PROCEDURE INTERNE CelciusToFahrenheit( t )
RENVOYER Conversion(t,"degré Celsius", "degré Fahrenheit")
FIN

 

// Conversion Celsius Fahrenheit sans procédure interne
// mais une "lambda" fonction à la place ...
tabFahrenheit.SupprimeTout()
tabFahrenheit = Map(tabCelcius, t=>{RENVOYER Conversion(t,"degré Celsius", "degré Fahrenheit")})
Trace(RC+RC+"Conversion Celsius Fahrenheit ...")
Trace("tabCelcius " + TableauVersChaîne(tabCelcius, ", "))
Trace("tabFahrenheit " + TableauVersChaîne(tabFahrenheit, ", "))

 

< Retour

7 commentaires

MindSoft
11/03/2020 - 11:28 - Répondre
A ce jour, les nouvelles fonctions Filter, Map et Agrège ne sont pas encore présentes dans l'aide en ligne. Merci Guillaume pour l'illustration pratique.

Mathieu Chevallier
22/05/2020 - 17:23 - Répondre
Les lambda c'est vraiment cool mais peux-t'on créer des procédures avec des fonctions en paramètre ? Avec ça on pourrait passer nos lambda à nos procédures ou à nos objets...

Mathieu
10/07/2020 - 22:31 - Répondre
Bonjour Guillaume, est-il possible d'implémenter ou de dériver une classe ou une interface afin de pouvoir avoir mon propre conteneur dans lequel je peux implémenter mes propres méthodes map(), filter() etc... ? Je pourrais avec ça passer des lambda fonctions. Par exemple votre objet tableau implémente t-il une interface pour les méthodes map et filter ? Autrement le concept d'interface fonctionnelle existe -t'il ? cela me permettrait de créer des méthodes dans lesquelles je peux passer des lambda.

Guillaume Bayle
13/07/2020 - 09:33 - Répondre
Bonjour, cette possibilité de surcharge n'est pas encore proposée, mais elle est suggérée à notre équipe développement ! J'espère que les implémentations nécessaires pourront être planifiées rapidement. Bons développements !

Guillaume Bayle
13/07/2020 - 09:34 - Répondre
Bonjour, cette possibilité de surcharge n'est pas encore proposée, mais elle est suggérée à notre équipe développement. J'espère que les implémentations nécessaires pourront être planifiées rapidement. Bons développements !

Guillaume Bayle
13/07/2020 - 09:35 - Répondre
Bonjour, cette possibilité de surcharge n'est pas encore proposée, mais elle est suggérée à notre équipe développement. J'espère que les implémentations nécessaires pourront être planifiées rapidement. Bons développements !

Eric COUTIER
22/01/2021 - 17:04 - Répondre
Bonjour, Ce serait encore plus fort si on pouvait faire des filter sur une chaine de caractères (donc il faudrait avoir une procédure qui renvoie un tableau de chaines contenant tous les caractères d'une chaîne) On pourrait alors traiter une telle chaîne par les lambda: Exemple: n'avoir que les chiffres d'une chaîne: MaChaine.VersUnTableau().Filtre(c => (c DANS (1,2,3,4,5,6,7,8,9,0)).VersChaine("")

Publier un commentaire : 
Votre adresse email ne sera pas publiée