Scala pour les développeurs Java
Ces jours-ci, j’explore plusieurs langages, et un que j’apprécie particulièrement est Scala. Fait intéressant : dépendant comment on l’utilise, il peut être très similaire ou très différent de Java. Dans cet article, je vous présenterai les similitudes afin de montrer comment un développeur Java pourrait vouloir transitionner (c’est une bonne première étape) vers ce langage.
Fonctionnel ou pas?
Tout d’abord, il est intéressant de noter que Scala a la réputation d’être un langage fonctionnel (comme Haskell, par exemple). Ce n’est pas faux de dire que le langage contient les outils qu’il faut pour faire de la programmation fonctionnelle, mais la “pureté” fonctionnelle n’est pas requise. En fait, il est tout à fait possible de rédiger du code qui serait relativement familier dans son intention à un développeur Java (mais de façon plus concise).
Scala est reconnu comme un langage multi-paradigme puisque l’on peut notamment faire de la programmation orientée-objet, de la programmation impérative ainsi que de la programmation fonctionnelle.
Qui l’utilise?
Lorsqu’on étudie un langage, il est toujours intéressant, puisque la programmation est foncièrement un acte social, de voir s’il y a une communauté et des entreprises qui l’utilisent. Parmi la liste des entreprises qui, à un moment ou un autre l’ont utilisé : Twitter, LinkedIn, The Guardian, FourSquare, etc.
Il est utilisé comme langage en production et parfois même en remplacement de d’autres langages (comme Ruby) lorsque ceux-ci ne sont plus “suffisants”. Il s’agit d’un langage qui existe maintenant depuis 12 ans et qui a acquis une certaine reconnaissance dans le milieu des développeurs.
Intéropérabilité avec Java
Un des éléments les plus intéressants, à mon avis, pour les gens qui réfléchissent à utiliser Scala, est que c’est un langage qui compile sur la JVM, comme Java, et que celui-ci est parfaitement intéropérable avec Java. Ainsi, on peut utiliser des classes Java en Scala et vice-versa de façon tout à fait naturelle. En fait, si on veut simplifier à l’extrême, pour ajouter Scala à un projet Java déjà existant, il suffit d’ajouter un JAR (ou une dépendance) à votre projet et vous êtes bons pour commencer.
Supposons qu’on a une classe Animal
qui est un objet en Java, il suffit de
faire un import de la dite classe en Scala pour l’utiliser:
import com.olivierlafleur.share.Animal;
//...
val animal = new Animal
Syntaxe
Scala est un langage fortement typé, tout comme Java, avec une inférence de type qui permet de souvent omettre les noms des types sans perdre le filet de sécurité qu’un typage fort permet.
Variables
Ainsi, lorsque l’on déclare une variable, là où en Java nous mettrions le type
du côté gauche de l’égalité, le type est automatiquement inféré. Ce que l’on doit
mettre est soit val
ou var
, dépendant si la variable est mutable ou non.
Cela nous permet donc d’enforcer l’immutabilité, si c’est ce que nous cherchons.
Par exemple, cette déclaration en Java :
Dragon dragon = new Dragon();
est remplacée par celle-ci en Scala :
var dragon:Dragon = new Dragon
//ou même ceci grâce à l'inférence de type
var dragon = new Dragon
Lorsque l’on veut déclarer un objet comme étant immutable (ce qui est en
général une propriété souhaitable en programmation fonctionnelle), en Java
nous devons utiliser l’opérateur final
alors qu’en Scala il suffit simplement
d’écrire ceci :
val dragon = new Dragon
Comme vous le remarquez sans doute, les points virgules ne sont pas nécessaires à la fin des instructions. Il suffit simplement de mettre chaque ligne de code sur sa propre ligne. De plus, on voit aussi que les parenthèses ne sont pas nécessaires à l’appel d’une fonction (ou d’un constructeur dans ce cas) s’il n’y a pas de paramètre.
Fonctions
Pour déclarer une fonction, il suffit d’utiliser le mot clé def
pour ce faire :
//:String n'est pas nécessaire puisque inféré
def mange(repas: String):String = "Votre dragon a mangé un " + repas
là où nous aurions écrit ceci en Java :
public String mange(String repas) {
return "Votre dragon a mangé un " + repas;
}
Cet exemple nous fait voir qu’en Scala, le return
n’est jamais obligatoire
puisque le résultat de la dernière ligne est retourné (et donc le type de retour
peut aussi être inféré).
Classes
Un des endroits ou Scala brille le plus, à mon avis, c’est dans la définition des
classes. En Java, nous avons à notre disposition des classes (class
) et des
interfaces (interface
).
En Scala, il y a trois types principaux : class
, object
et trait
.
De façon simpliste, trait
est comparable aux interfaces en Java et class
est comparable à une classe,
mais sans les éléments qui seraient static
en Java. L’élément object
, quant
à lui, contient ceux-ci.
Tout comme les interfaces en Java 8, les traits peuvent avoir des fonctions qui ont une implémentation. Par exemple :
trait PeutManger {
def mange():Unit
def digerer() = "Miam, c'était délicieux"
}
En Java, cela aurait l’air de ceci :
public interface PeutManger {
void mange();
default void digerer() {
System.out.println("Miam, c'était délicieux");
}
}
Maintenant, créons-nous, dans les deux cas, un objet ordinaire (POJO) avec des getter/setter, l’implémentation d’une “interface” et une fonction statique qui agit comme un Builder.
En Java :
public class Dragon implements PeutManger {
private String nom;
private int age;
public Dragon(String nom, int age) {
this.nom = nom;
this.age = age;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void mange() {
System.out.println("Votre dragon " + nom + " a mangé");
}
public static Dragon construireDragon() {
return new Dragon("Ami", 42);
}
}
devient en Scala :
class Dragon(_nom: String, _age: Int) extends PeutManger {
def nom = _nom
def age = _age
def age_= (value:Int) = age = value
def nom_= (value:String) = nom = value
override def mange() = println("Votre dragon " + _nom + " a mangé")
}
object Dragon {
def construireDragon() = new Dragon("Ami", 42)
}
En terme de bénéfice additionnel, en plus d’être (à mon goût) plus élégant comme
code, le “setter” en Scala permet de faire directement une assignation grâce à
la syntaxe dragon.age = 15
, par exemple, mais en passant par le biais d’une
fonction.
Conclusion
Dans cet article, nous avons abordé la base de Scala d’un point de vue des similitudes du langage à Java. Cela nous permet de faire une première approche du langage qui permette de nous familiariser avec la structure de ce langage. Dans le prochain article, nous commencerons à explorer les éléments particuliers de Scala qui nous permettent d’utiliser de nouveaux outils dans la résolution de nos problèmes informatiques.
Merci à JC Larivière, Joël Trottier-Hébert et Jni Viens pour leurs commentaires, qui m’ont permis d’améliorer cet article.