Accueil Nos publications Blog Devoxx 2012 – Effective Scala

Devoxx 2012 – Effective Scala

Ces derniers mois, le langage de programmation Scala a fait beaucoup parler de lui. Plusieurs conférences lui étaient naturellement consacrées à la conférence Devoxx à Anvers.
Je vais revenir sur une présentation que j’ai beaucoup aimée: Effective Scala , de Joshua Suereth.

Le titre ce talk vous évoque sûrement le livre bien connu sur Java ‘ Effective Java ’ de Joshua Bloch. L’objectif de la présentation était de rappeler les bonnes pratiques en Scala afin d’en optimiser son utilisation et d’être plus réactif face à d’éventuelles problématiques. Voici quelques-unes de ces bonnes pratiques énoncées par Joshua Suereth : ‘Use expressions, not statements !’, ‘Stay Immutable !’, ‘Use Option !’, ‘Use the REPL !’, ‘Use type traits !’, ‘Limit the scope of implicit’, ‘Use def for abstract members’, ‘Annotate API or non trivial return types’, ‘Use type traits’, ‘Avoid implicit views, … don’t learn it !’ …

Dans cet article, je vais en aborder certaines d’entre elles.

Petits rappels sur Scala

Scala est un langage de programmation, qui a été créé en 2003 par Martin Odersky, professeur à l’EPFL.
Voici en quelques mots les spécificités de ce langage :
– Scala est un langage multi-paradigmes : il intègre à la fois le paradigme de programmation orienté-objet et celui de la programmation fonctionnelle
– Scala peut s’exécuter sur une JVM, et est compatible avec l’utilisation de librairies Java
– comme Java, Scala est statiquement typé. De plus tout est objet et hérite de la classe “Any”
– la syntaxe de Scala est proche de celle de Java, mais moins verbeuse.

Les bonnes pratiques évoquées par Joshua Suereth

‘Use expressions, not statements!’

C’est probablement la règle la plus basique selon Joshua : en Scala, il faut penser expressions plutôt que déclarations. Revenons tout d’abord sur la différence entre ces deux syntaxes : une déclaration exécute du code. Une expression quant à elle, évalue du code. De plus, et c’est un point très important, toute expression retourne une valeur (le résultat de la dernière ligne exécutée), ce qui rend superflue l’utilisation du mot-clé return en Scala.

Dans la pratique, on se retrouve régulièrement dans le schéma suivant en Java : on commence par créer une variable, du code est ensuite exécuté. Puis lors de ce traitement, une valeur est associée à la variable, qui est retournée à la fin de la méthode. Il est tout à fait possible de coder de cette façon en Scala. Cependant, ce serait ignorer certaines des caractéristiques du langage.

Voici un premier exemple en Scala, codé “façon Java” :


    def max(x: Int, y: Int) : Int = {
      var max:Int = 0
      if (x > y)
        max = x
      else
        max = y
      return max
    } 

Dans ce second exemple : plus de return, ni de variable locale. On pense expression ! A noter également que le type de retour Int de la méthode n’est pas obligatoire car le compilateur Scala fait de l’inférence de type.


    def max(x: Int, y: Int) {
      if (x > y)
        x
      else
        y
    } 

On remarque par ces exemple simples, un gain de ligne en codant à l’aide des expressions plutôt qu’avec des déclarations, et ceci sans avoir rendu le code moins lisible. Cette syntaxe est certainement l’un des atouts du langage Scala, mais aussi l’une de ses faiblesses et Joshua Suereth n’a pas manqué de nous le rappeler : la concision du code ne doit pas se faire au détriment de sa lisibilité.

‘Use the REPL’

Le REPL ( Read-Evaluate-Print Loop ) est un interpréteur pour Scala. C’est un shell intéractif qui compile du code et retourne des résultats et des types. Autrement dit c’est un outil indispensable pour tous ceux qui veulent se mettre à Scala ! Joshua Suereth nous a rappelé quelques-unes de ses fonctionnalités.

Voici à quoi ressemble cette fameuse console :

Tout d’abord, pour chaque déclaration effectuée, le REPL renvoie une variable, nommée  res0 , ainsi que son type, comme l’illustre l’exemple ci-dessous :

De plus, on peut directement définir des classes, leurs méthodes…faire des imports de librairies Java dans le REPL, puis tester le code écrit. Enfin, une fois ce code validé, il est possible de le copier dans les fichiers sources de notre projet en utilisant l’historique du REPL.

Pour finir, en utilisant un outil de build, comme SBT, il est possible de lancer le REPL afin d’accéder à un projet bien précis, d’en voir ses sources, lancer ses tests et faire des modifications.

Le REPL est donc un outil très puissant à utiliser sans modération !

‘Stay Immutable!’

Une problématique bien connue des développeurs, est celle de la concurrence. On est en effet amené à travailler avec des variables dites mutable, autrement dit des variables qui une fois initialisées peuvent changer de valeur. Comment savoir dans quel état est laissée une telle variable suite au passage de threads ?

Le langage Scala offre la possibilité de déclarer qu’une variable soit immutable en ajoutant le mot-clé val devant une variable, soit mutable avec le mot-clé var. En Java, l’état immutable correspond au mot clé final.

Un des intérêts des objects immutables est de se prémunir d’éventuels problèmes de concurrences. De plus, ils offrent une meilleure sécurité que les objets mutables en garantissant leur état. Enfin, la définition d’égalité se voit facilitée grâce à l’immutabilité, et les notions de co/contra variances prennent tout leur sens.

‘Use Option’

En Scala, il existe un type “Option”. Ce type dénote un objet qui hérite soit de “Some” soit de “None”. En une phrase, le type “Option” permet de dire que l’on attend potentiellement aucune valeur, et dans ce cas-là on aura un objet de type “None”.

Prenons l’exemple d’une authentification lors d’une connexion à un compte sur un site avec des droits différents suivant les utilisateurs.


    def authentification(
session: HTTPSession,
username: Option[String],
password: Option[Array[char]]) =
    for { u <- username
      p <- password
      if canAuthentifier(u, p)
        privileges <- privilegesFor.get(u)
    } injectPrivileges(session, privileges)

    

Le type “Option” nous assure que le username et/ou password ne seront jamais null, mais au pire de type “None” si aucune valeur n’est présente.

Au final, les Options permettent de gérer des cas limites et d’améliorer la qualité du code en se prémunissant des NPE (NullPointerException). Et puis ça nous évite de mettre des contrôles if != null de partout ;-).

’Limit the scope of implicit !’

En Scala, on a la possibilité de définir des variables ou méthodes comme implicit. Ceci indique au compilateur que ces variables/méthodes pourront être utilisées dans le cas de ‘résolutions implicites’. D’autre part, ce mot-clé s’applique aussi sur la liste des paramètres d’une méthode, ce qui indique que cette liste pourrait être manquante et devrait alors faire appel à une ‘résolution implicite’. Oui, mais c’est quoi une résolution implicite ?

Dans l’exemple ci-dessous, on commence par définir une fonction qui en paramètre prend un ‘Int’ taggé implicit. On définit ensuite un Int implicit. Au moment où l’on appelle la fonction carre, aucun argument n’est précisé : le compilateur va donc aller chercher un ‘Int’ dans le scope des implicits. Il trouve 5 et peut ainsi retourner le résultat de la fonction carre, à savoir 25. C’est le mécanisme de résolution implicite :-).

Notons que si plusieurs implicits sont présents dans le scope des implicits pour un même type (oui c’est possible :-)), il y aura une ambiguïté pour le compilateur, qui renverra le message d’erreur ci-dessous :

Dans ce cas-là, il suffit de préciser l’implicit que l’on souhaite utiliser, et ça marchera. Cet exemple montre une des limitations des implicits : dans la pratique c’est une gymnastique pour se rappeler de ce qui est présent dans le scope des implicits, et ça peut rendre l’utilisation des implicits moins optimale.

Notons également qu’il est tout à fait possible de passer un argument non implicit à une fonction qui prend en argument un implicit :

Bilan

J’ai beaucoup aimé cette présentation, déjà parce qu’elle était drôle, et puis parce qu’elle rappelait des concepts clé à bien avoir en tête lorsqu’on veut coder en Scala. Je l’ai trouvée très instructive et la conseille à tous ceux qui se lancent dans ce langage de programmation.

Pour résumer, l’idée principale que je garderai en tête est que même si Scala de part plusieurs de ses caractéristiques (inférence de type, syntaxe expressive…) permet d’obtenir un code plus concis, il ne vaut pas en abuser au risque d’être confronté à un code illisible (c.a.d non compréhensible, ou du moins qui donne très mal à la tête 🙂 ). Le one-liner c’est bien, mais ça doit rester accessible aux développeurs qui pourraient avoir à maintenir ce code !