Créé en 2003 par l’Ecole polytechnique fédérale de Lausanne, Scala est un langage de programmation qui vise à réunir la programmation orientée objet et fonctionnelle afin de répondre aux différentes problématiques de projet. Très utilisé dans le domaine de l’analyse de données avec notamment le Framework Spark, il fournit l’infrastructure de base pour des sites tels que Twitter, LinkedIn, Netflix et Airbnb. 

 

Compilé en bytecode Java (exécutable sur la JVM), Scala offre la possibilité d’utiliser les librairies écrites en Java sans code supplémentaire. Cela lui permet non seulement de bénéficier de la maturité et de la diversité de ces librairies, mais facilite surtout la transition entre ces deux langages pour les développeurs.

 

POO

 

Scala s’est beaucoup inspiré de Java et reprend la plupart de ses concepts. Nous pourrions même (avec exagération) dire que l’on programme en Scala exactement de la même manière qu’en Java, en enlevant simplement les points-virgule dans le code. Nous pouvons constater néanmoins des différences avec cet exemple:

 

1.png

 

  • Il existe deux catégories de valeur: val (la valeur ne peut pas changer, comparable à final en Java) et var. (une variable que l’on peut redéfinir);
  • Scala pousse encore plus loin la logique orientée objet: Il n’existe pas de types primitifs tels que int ou double. Ce sont des classes en Scala: Int et Double;
  • La classe de la valeur n’est pas obligatoirement précisée: le compilateur peut le deviner en se basant sur la valeur;
  • Les points-virgule ne sont pas obligatoires;
  • On utilise le mot-clé def pour déclarer une méthode: le type de retour n’a pas besoin d’être précisé; Les accolades (lorsque la méthode ne contient qu’une seule opération) et le mot-clé return (on renvoie la dernière expression évaluée) sont facultatives;
  • La classe peut prendre des paramètres. Ces derniers deviennent des attributs de la classe. Cela remplace le constructeur en Java;
  • Le mot-clé public n’existe pas: c’est la visibilité par défaut.

En plus de ces différences de syntaxe, il existe plusieurs particularités en Scala pour implémenter différents objets:

 

  • case class pour générer en une seule ligne une classe simple contenant des données, accesseurs et quelques méthodes utilitaires (equals, hashCode, toString, copy):

2.png

  • Les traits, équivalents des interfaces en Java:

3.png

*A et B définissent chacun la même méthode. On redéfinit alors explicitement la fonction en question, avec le mot-clé override pour éviter une erreur de compilation. 

 

  • Le mot-clé static n’existe pas en Scala. Le mot-clé object est utilisé (à la place de class) pour créer un singleton:

4.png

*On utilise du String Interpolation dans la méthode message

 

object pourrait cependant avoir une utilité bien différente, lorsqu’on le crée avec une class portant le même nom dans le même fichier (on l’appelle companion object).

 

5.png

6.png 

 

Cette implémentation permet de créer une Person sans le mot-clé new. La classe peut accéder aux attributs ou méthodes privés dans cet object. On peut séparer les méthodes statiques d’une classe dans son companion object ou y implémenter les patterns Factory et Builder.

 

Programmation fonctionnelle

 

L'une des plus grandes caractéristiques de Scala est son côté programmation fonctionnelle. Une fonction est considérée comme une objet premier, au même titre qu’un Int ou String, et peut être passée en paramètre dans une autre fonction: 

 

7.png

 

Nous avons déclaré une liste de personnes. Ensuite, la méthode map applique la fonction passée dans son paramètre (getName() dans notre cas) à tous les éléments de la liste. Nous obtenons donc une liste de String (contenant le nom de chaque personne). 

Notez que people est immuable, le résultat est une liste transformée à partir d’une copie de people. C’est une approche recommandée en Scala car elle évite les effets de bord (les impacts sur les données pendant l’exécution du programme) et facilite la modification successive d’un objet par plusieurs threads.

 

Il existe des types dits monadiques en Scala, caractérisés par la présence des méthodes map (la même que celle de la List) et flatMap. Parmi ces types, Option est le plus souvent utilisé (équivalent de Optional en Java 8): 

8.png
9.png

Option[T] est un type abstrait. C’est un container de zéro (None, comparable à null en Java) ou d’un élément de type T (Some[T]). Dans la méthode findByName(…), si nous trouvons un élément Person qui remplit la condition, nous renvoyons Some[Person], sinon None. La méthode map prend une fonction et l’applique à l’élément dans l’option. Elle renvoie Some[String] ou None. Enfin, la méthode getOrElse sert à récupérer l’élément de Some[String] ou son expression en argument en cas de None.

 

10.png

 

flatMap est différente de map: pour Option[A], map prend en argument une fonction f: A => B et renvoie Option[B]; flatMap prend une fonction f: A => Option[B] et renvoie Option[B]. Dans la méthode flatMap ci-dessus, on a une fonction qui prend en argument tom: Person et retourne Option[String] donc flatMap aussi retourne Option[String]. Cette approche fonctionnelle permet d’obtenir un résultat en une seule ligne de code au lieu d’une imbrication de plusieurs opérateurs ternaires. 

 

Pattern matching est une autre fonctionnalité très puissante en Scala:

 

11.png

Dans cette utilisation, le mot-clé match Scala remplace simplement switch en Java. Rien d’extraordinaire au premier abord. Sauf que son fonctionnement s’étend jusqu’à reconnaître le type des données comparées:

12.png

13.png 

 

Cela offre plusieurs possibilités d’utiliser le pattern matching en Scala et facilite donc l’écriture des fonctions alternatives basées sur la comparaison des valeurs, des collections ou des types.

 

Une dernière fonctionnalité très appréciée en Scala est la for comprehension. Elle permet de faire une itération simple, comme la boucle for en Java:

14.png

Cependant, for … yield … pourrait être bien plus puissante qu’une simple itération. Il est possible de faire des boucles imbriquées avec:

 

15.png

 

Outre les collections, la for comprehension fonctionne aussi sur d’autres types de valeur comme les options. Nous allons implémenter l’expression flatMap que l’on a vu précédemment:

 

16.png

 

La for comprehension est automatiquement traduite par le compilateur Scala en expression utilisant une combinaison de map et de flatMap.

 

Apprendre Scala ?

 

Scala a été développé dans le but de créer un langage multi-paradigme:

 

  • D’un côté, Scala hérite de toutes les possibilités d’un langage OO (on pense à Java, que l’on ne présente plus): héritage, polymorphisme, exceptions… ces concepts sont très utilisée dans l’industrie; 

 

  • De l’autre côté, la programmation fonctionnelle, qui permet de faire disparaître les effets de bord, en proposant des concepts simples : immutabilité d'une variable et utilisation de fonctions dont le résultat ne dépend que de ses paramètres (très simples à tester). 

 

Ces deux paradigmes sont combinés de manière parfaitement harmonieuse. Cela nous permet de faire des évaluations complexes avec des lignes de codes compactes et une syntaxe épurée.

 

Pour ma part, j’ai découvert Scala durant l’une de mes dernières missions (plutôt “redécouvert” car j’en avais fait très brièvement quand j’étais étudiant) et j’ai pris beaucoup de plaisir à travailler avec ce langage. Je l’ai trouvé très simple à lire et j’ai été agréablement surpris par ce que l’on peut réaliser en aussi peu de lignes de code. Même si la programmation fonctionnelle nous demande d’approcher les problèmes ou concevoir des applications d’une nouvelle manière, nous pouvons profiter rapidement des meilleurs aspects de ces deux paradigmes une fois cette étape franchie.

 

Depuis un an, Scala a perdu un peu de son attrait pour les développeurs. Les évolutions de Java (Java 8) et la montée de Kotlin, un langage plus proche de Java, y sont sans doute pour quelque chose. Cependant, il est toujours intéressant d’apprendre Scala, d’une part pour découvrir la programmation fonctionnelle, d’autre part pour ses frameworks et ses bibliothèques: 

 

  • Play, un puissant framework pour écrire des applications web en Scala qui se focalise sur la productivité des développeurs; 
  • Akka, une bibliothèques qui se base sur le modèle du système d’acteur d’exécution concurrentielle (pour répondre aux problématiques des modèles de multi-threading bloquant); 
  • Apache Spark, un outil d'analyses unifiées ultra-rapide pour le big data et le machine learning. 

 

En définitive, ces frameworks et bibliothèques restent très réputés dans le monde de l’entreprise et constituent un atout majeur pour ce langage.