Introduction à Scala

Depuis quelque temps, Scala fait beaucoup parler de lui … et les avis sont plutôt partagés. Ce billet inaugure une série destinée à présenter ce langage de programmation multi-paradigmes.

Scala est un langage de programmation visant à concilier les paradigmes objets et fonctionnels au travers d’un langage qui se veut plus simple et élégant.

Après une rapide présentation des principes de Scala, ce billet traitera du mécanisme d’inférence en Scala.

Principes de Scala

En opposition à la programmation impérative, le modèle de programmation fonctionnelle propose de s’affranchir de la notion d’état et d’écrire un programme comme une imbrication de fonctions. Une fonction est ici considéré comme un élément possédant plusieurs paramètres d’entrée et un et un seul paramètre de sortie. La façon de concevoir les algorithmes dans le paradigme fonctionnel est donc différente de ce à quoi la plupart d’entre nous sommes habitués et risque d’en rebuter plus d’un.
Néanmoins, Scala permet de concilier ce mode de programmation avec la programmation orientée objet. On y retrouve notamment les notions de classes, et l’interaction avec le langage Java. L’objectif de Scala est de tirer parti du meilleur des deux mondes :

  • Moindre verbosité et meilleure gestion de la mémoire d’un côté ;
  • Structuration des données et richesse des APIs de l’autre.

Parmi les notions de Scala, nous retiendrons les suivantes :

  • Plus de constructeur : une économie sur l’instanciation est faite (pas besoin de « new »).
  • Le type d’une variable peut être inféré, ainsi le type peut être omis à certains endroits.
  • Possibilité de faire des « mixin class » : les mixins Scala sont similaires aux interfaces Java dans le sens où celles-ci définissent des contrats à implémenter. La différence réside dans le fait qu’il est possible de définir des implémentations par défaut (notion de classes abstraites) pour les méthodes du mixin. Il est ainsi possible de faire de l’héritage multiple.
  • Le compilateur Scala génère des .class pouvant être exécutés dans une JVM.
  • Interaction avec Java : par exemple, toutes les classes de java.lang sont importées par défaut et il est possible d’en importer d’autres explicitement.

Le mécanisme d’inférence

En Scala, la déclaration d’une variable se fait de la manière suivante variable:Type :

var myStr:String = 'xebia'

Scala possède le mécanisme d’inférence et donc il est possible d’écrire cette déclaration de la manière suivante :

var myStr = 'xebia'

La construction d’une liste :

val listStr: Array[String] = new Array[String](4)

Ici la variable listeStr est de type Array[String] et est initialisé avec une longueur de 4. Néanmoins, Scala permet de simplifier cette déclaration (mécanisme d’inférence) et nous avons alors :

val listStr = new Array[String](4)

Au passage nous avons un concept important du mot clé val en Scala. Lorsqu’une variable est définie avec val, celle-ci ne peut pas être réassignée (ie listStr sera toujours un Array[String]). Néanmoins, l’objet auquel elle se réfère peut être mutable (ie les éléments de la liste peuvent être modifiés).

Ensuite le remplissage de la liste :

listStr(0) = "Bonjour"
listStr(1) = "Hello"
listStr(2) = "Guten Tag"

Le parcours de cette liste se fait de la manière suivante :

for (i <- 0 until listStr.length)
    println(listStr(i))

On parcourt la liste jusqu'à sa longueur (listeStr.length) et on affiche les éléments de la liste.

A travers ces exemples, nous remarquerons que la manipulation des listes se fait par le biais de parenthèses et non de crochet (ie Java). Cela est un autre concept de Scala. La magie réside dans le fait que lorsque des parenthèses sont appliquées à une variable, Scala va les « transformer » en appel de méthodes. Ainsi si nous reprenons les exemples précédents Scala fera :

listStr.update(0,"Bonjour")
listStr.update(1,"Hello")
listStr.update(2,"Guten Tag")

for (i <- 0 until listStr.length)
	println(listStr.apply(i))

Il est tout à fait possible d'écrire directement ce code, mais le langage Scala permet de simplifier l'écriture de code sans que des problèmes de performances interviennent.

Enfin pour finir un exemple avec une HashMap :

val factories = new HashMap[Int, String]
factories += 1-> "Xebia Hollande"
factories += 2-> "Xebia France"
factories += 3-> "Xebia Inde"
factories += 4-> "Xebia Groupe"
println(factories(2))

La première ligne signifie que la variable "factories" sera une HashMap avec des clés de type Int et des valeurs de type String.

Ensuite l'opérateur += permet d'ajouter les clés/valeurs avec la méthode ->. Cela peut donc s'écrire :

1.->("Xebia Hollande")

Ici cela signifie que la méthode -> est appelée sur un Int dont la valeur est 1 et prenant en paramètre un String de valeur "Xebia Hollande".

Conclusion

Cette introduction a permis de voir un des concepts clés du langage Scala, le mécanisme d'inférence. Celui-ci permet donc d'avoir une programmation simplifiée tout en ne négligeant pas la performance. Scala ne semble pas si complexe qu'il semblerait l'être, preuve en est les exemples de cet article, où l'on voit qu'il est possible de programmer comme en Java avec une simplification syntaxique. Bien entendu, Scala permet une écriture « moins objet » et plus fonctionnelle et le but de cet article est de poser les bases. D'autres articles suivront avec des notions plus complexes sur le langage Scala.

Références :

5 commentaires

  • Concernant le côté fonctionnel de Scala, et le fait que ce soit un langage à objets, ça me fait furieusement penser à Ruby, qui offre le même genre de fonctionnalités.
    La grosse différence à mon sens, est que Scala semble être taillé pour être embarqué dans la JVM.

    Bon, il y a quand même des idées curieuses (genre le Array[String](4), là où Java nous propose le String[4]), mais j’imagine qu’il s’agit seulement d’une n-ième d’itération de « mon herbe est plus verte que la tienne ».

  • Vu ce qu’on peut faire avec le pattern Strategie, j’espère beaucoup des prochains frameworks en scala .
    Style http://demo.liftweb.net/lift/ajax
    (et décidément on regarde les mêmes choses : wicket, scala… Ce que c’est que la mode chez les early adopters quand même!…)

  • Ce blog est vraiment bien : encore une techno que je surveille depuis quelques temps qui se retrouve traitée ici. Ou alors, je partage beaucoup de points d’intérêts avec les différents auteurs :) Merci pour cette série d’article annoncées. vous pourrez même faire un merge avec celle sur les frameworks web en traitant de Lift (http://liftweb.net/) , le framework full-stack Web écrit en Scala, intégrant Cometd qui monte qui monte…

    Au niveau des sources traitant de Scala, il faut rajouter « Lambda the ultimate » qui a une section dédiée à Scala depuis assez longtemps (http://lambda-the-ultimate.org/taxonomy/term/32), et de très nombreux blogs dont par exemple Beautifull Language qui a fait une série d’article intéressants (http://langexplr.blogspot.com/search/label/scala) et celui de Tony Morris, qui traite beaucoup de Scala (http://blog.tmorris.net/).

    @Nicolas Delsaux:

    Le côté fonctionnel de Scala est beaucoup plus marqué que dans Rubis, même si ca ne se voit pas au premier coup d’oeil. Cela peut se remarquer en particulier par l’accent qui est mis sur les méthodes non mutables. Par exemple, le type List (pas celui présenté) est non mutable : les modifications sur une List se font en créant de nouvelle List. Scala possède aussi des « val », comme présenté ici, qui sont des variables non ré-assignable.
    Ensuite, Scala possède des fermetures (closures) qui sont utilisées par exemple pour la création de nouveau opérateurs.
    Scala permet de faire du pattern matching sur les classes (et rien que pour cela, ca vaut le coup de regarder Scala !). Scala permet définir des méthodes sous forme Curryfiée (ce qui est tout simplement géniale pour définir des API).
    Enfin, le côté fonctionnel transparaît par les API proposées : on est encouragé à manipuler des listes pour toutes les opérations de bases. Par exemple, il n’y pas de « for » en Scala, son remplaçant étant une closure sur des listes (sur laquelle on peut appliquer toutes les opérations fonctionnelles standards, telles que filtres, map, etc)

    Bref, là où Rubis a introduit quelques notions fonctionnelles, Scala a été construit dès le début pour être un merge la plus profond possible entre paradigme Objet et paradigme fonctionnel. Pour le côté Objet, c’est plutôt très bien réussi, pour le côté fonctionnel, on est pas encore à Haskell, ni même OCaml.

    Mais surtout, surtout, la plus grande différence entre Scala et Rubis est que Scala est un langage typé statiquement, ce qui est bien, alors que Rubis est typé dynamiquement (non non, ma préférence ne transparait pas ;)

    Pour ce qui est du « Array[String](4), là où Java nous propose le String[4] », c’est tout simplement dans un soucis d’homogénéité du langage (ca se verra plus si un article présente les « génériques » façon Scala). Là construction « Array[String](4) » est tout simplement un objet Array, paramétré par le type String, pour lequel on appelle le constructeur (int length) qui construit le tableau de longueur donnée.
    On retrouve se soucis d’homogénéité du langage à de très nombreux endroits : les opérateurs ne sont pas des éléments spéciaux du langage mais de simples méthodes (ce qui facilite vraiment la vie pour définir ses propres API avec ses opérateurs, l’exemple des Actors Scala est frappant pour cela), *tout* est objets (pas de types primitifs), etc…)

    @Gabriel
    Jette un oeil à Tapestry 5 ( http://tapestry.apache.org/tapestry5/ ), tu pourrais être bluffé (mon rêve : lift, avec la vision de Howard pour l’archi. Ce mec est une brute comme j’en ai rarement vue).

    Voilà voilà, merci Xebia pour ce blog

    Francois

Laisser un commentaire