Le langage Scala

Programmation fonctionnelle

Le langage Scala tire une partie de sa force dans sa capacité à être programmé avec le paradigme fonctionnel. Cette partie a pour objectif d'introduire le paradigme de programmation fonctionnelle, d'indiquer ses principaux atouts et principaux défauts, et enfin de présenter les différents outils et solutions que propose un langage fonctionnel.

Qu'est-ce que c'est ?

L'écrasante majorité des langages de programmation utilisés dans l'industrie sont du type «impératif». Cela signifie que l'exécution d'un programme peut être représenté par une machine à état, chaque opération effectuée par le programme faisant changer le programme d'état.

Pourtant, le paradigme de programmation fonctionnelle existe lui-aussi depuis les débuts de l'informatique mais n'est que très peu utilisé dans l'industrie. Un programme écrit de façon fonctionnelle ne change jamais d'état comparé au paradigme impératif. Un programme fonctionnel peut être décrit par un ensemble de fonctions imbriquées les unes dans les autres. Ces concepts d'états et de fonctions sont des représentations mathématiques; la lecture de cette partie permettra d'avoir une compréhension plus technique et moins théorique de la différence entre ces deux paradigmes.

Des données non-mutables

Une des règles de base d'un langage fonctionnel est de ne pas permettre l'utilisation de données mutables. Cela passe d'abord par l'impossibilité de réassigner une nouvelle valeur à une variable; une variable gardera alors toujours la même valeur tout en long du programme. Cela passe ensuite par l'utilisation de structures de données non-mutables. Les «objets» de la programmation orientée objet ne déroge pas à cette règle : ils doivent aux-aussi être non-mutables.

Dans un langage fonctionnel, l'utilisation du mot «variable» peut paraître étrange pour qualifier des conteneurs de données qui ne varient pas. Cependant, les auteurs des différentes sources litéraires qui ont permis de réaliser cette présentation parlent eux aussi de variable. De plus, la vision de ce qu'est une «variable» dans un langage de programmation est claire pour la communauté des programmeurs. Cette présentation utilisera le mot «variable» même pour parler d'un conteneur de données invariantes.

Listes

Les «tableaux» sont des structures de données mutables utilisées dans la programmation impérative. Comme il s'agit d'une structure mutable, il faut la remplacer par son pendant non-mutable dans un langage fonctionnel. Le choix du mot «liste» pour désigner un tableau non mutable est le choix qui a été fait dans de nombreux langages fonctionnels, notamment Scala. Dans la suite de cette présentation, un «tableau» sera toujours mutable, et une «liste» désignera toujours un tableau non-mutable.

Les tableaux et les listes se différencient par le fonctionnement des fonctions qui les manipulent. Les deux exemples suivants permettent d'illustrer ce propos.

Exemple 1 - Modification de la valeur associée à la n-ème cellule d'un tableau et d'une liste

Exemple 2 - Ajout d'un nouvel élément à la fin d'un tableau ou d'une liste

Tuples et tables associatives

Avec le temps, de nouvelles structures de données basiques mais indispensables ont fait leur apparition dans les langages de programmation : les tuples et les tables associatives. Ces structures de données ne sont pas spécifiques à la programmation fonctionnelle, et peuvent donc être mutables ou non-mutables selon l'implémentation. Dans cette partie ne sera traitées que les implémentations non-mutables.

La première strucure de données est le tuple, qui est une liste qui peut recevoir une valeur de n'importe quel type (entier, chaîne de caractères, liste, tuple, etc). Les implémentations non-mutables des tuples fonctionnent comme les listes : tout modification du tuple engendre sa copie, la modification de cette copie puis le renvoie de cette copie à l'utilisateur.

Les tables associatives permettent de stocker un couple clé-valeur, la valeur pouvant être accédée en fournissant la clé mais pas le contraire. Comme pour les listes et les tuples, l'implémentation non-mutable des tables associatives renvoient une copie d'elles-même modifiée pour chaque opération de modification. En Scala, le nom retenu pour désigner une table associative non-mutable est «set».

Les fonctions

Effets de bord

Les «effets de bord» en programmation est un terme désignant des modifications faites sur des données pendant l'exécution d'une partie d'un programme. Les effets de bord ne posent pas de problèmes en soi, mais peuvent être sources de confusion à partir du moment où la partie du programme impacte des données qui ne paraisse pas lui être directement liée. En programmation impérative, l'utilisation de fonction peut générer des effets de bords. L'exemple suivant, écrit en C, en est une illustration :

int i = 0;

int increment() {
	return i++;
}

int main() {
	printf("%d\n", increment()); /* Affiche 0 */
	printf("%d\n", increment()); /* Affiche 1 */
	
	return 0;
}

Sur l'exemple ci-dessus, la fonction increment() impacte la variable i, ce qui génère un «effet de bord» sur celle-ci. Dans cet exemple, le plus désagréable est de remarquer que sans lire le code de la fonction, il est impossible de deviner que la variable i est modifiée.

Approche «fonctionnelle» des fonctions

En programmation fonctionnelle, les fonctions travaillent comme des fonctions mathématiques dans le sens où elles renvoient toujours le même résultat si les mêmes paramètres lui sont données. Par exemple, la fonction mathématique f(x) = x² renvoie toujours 4 quand la variable x est égal à 2. Dans l'exemple précédent, la principale gène venait du fait qu'une des variable impactée n'était même pas passée en paramètre à la fonction. Il n'y a plus ce problème en programmation fonctionnelle : pour que la fonction renvoie toujours le même résultat, il faut obligatoirement donner tous les paramètres à la fonction.

De plus, puisque la valeur associée à une variable ne peut pas changer, le programmeur a la certitude que la fonction qu'il lance n'ira pas modifier une variable quelque part dans le programme, ni que sa fonction va utiliser une variable dont la valeur aurait changée depuis son assignation.

Enfin, en programmation fonctionnelle, les fonctions ont les mêmes «droits» que les valeurs associées à des variables : elles peuvent être stockées dans des variables, peuvent être passées en paramètre à une fonction, être retournées par une fonction, mais aussi être déclarées au sein d'une autre fonction.

Conclusion

La programmation fonctionnelle permet de faire disparaître les effets de bord des programmes en proposant des concepts simples : interdiction de modifier la valeur d'une variable, et utilisation de fonction dont le résultat ne dépend que de ses paramètres.

De plus, les fonctions écritent de manière fonctionnelle deviennent très simples à tester puisque le résultat doit être toujours le même à paramètres égaux. Les fonctions peuvent donc être testées en dehors de l'exécution d'un programme, pendant la phase de développement d'une application par exemple.

Cependant, il est important de noter qu'il est impossible de faire un programme purement fonctionnel. En effet, l'écriture sur un périphérique comme un écran ou une imprimante est considéré comme un effet de bord puisque cela déclenche un changement d'état. La solution est de rassembler toutes les lignes de code non-fonctionnelle afin d'obtenir une «partie critique» du programme, partie qui sera ainsi facile à relire et éventuellement à corriger.