mars
2008
Je compte faire une série de billets pour présenter Scala, mais ce billet est plutot une sorte de teaser, qui présente quelque unes des constructions Scala qui m’ont impressionné jusque là.
Les exemples présetns ici ne seront donc pas bien documentés ou expliqués, mais ils serviront juste à montrer la puissance du langage Scala.
Je vais présenter les singletons, l’AOP et le lazy fetch.
Singletons:
Scala offre ni plus ni moins qu’un support en natif des singletons, evitant ainsi d’avoir à coder la chose à la main, des choses du genre:
Java
public class SingletonFacory {
private static Object singleton;
public synchronized static Object getSingleton() {
if (singleton == null) {
singleton = new Object();
}
return singleton;
}
}
Ou encore passer par un conteneur comme Spring.
Ce que ça donne en Scala ?
Rien en particulier, suffit de déclare l’objet en question comme object au lieu de class, ce qui donne:
Scala
object TheSingleton {
//les champs
}
C’est tout !
Suffit d’y accéder par son nom, n’importe où dans l’application, et on est sur d’avoir la même instance partout.
AOP
Scala offre en natif une notion très proche de l’AOP, qui est les traits.
Prenons les traits suivant:
Scala
trait Action {
def doAction
}
trait LogAction extends Action{
abstract override def doAction = {
println("Before Action")
super.doAction
println("End Action")
}
}
trait RetryAction extends Action{
abstract override def doAction = {
println("Try Action")
try{
super.doAction
println("End Try Action")
} catch {
case e: Error => {
try{
println("Retry Action")
super.doAction
println("End Retry Action")
} catch {
case e: Error => println("Failed retry")
}
}
}
}
}
Les traits sont une sorte d’interfaces à la Java mais qui peuvent contenuir des implémnetations (c’est pas de l’héritage multiple rassurez vous, c’est les mixins, mais j’y reviendrais dans un autre billet).
En gros, j’ai défini un tait Action qui déclare la méthode doAction ainsi que deux traits (LogAction et RetryAction) qui implémentent Action, le premier affiche des messages avant et après avoir invoqué la méthode doAction du parent, et le second invoque doAction du parent, et si ça echoue (lance une exception), relance une deuxième fois la méthode)
Maintenat, disons que l’on dispose d’une cette implémentation de Action :
Scala
class TestAction extends Action{
def doAction = {
println("Real Action")
if(List(1, 2).size==2)
error("Stupid error");
}
}
Cette action ne fait qu’afficher un message et lancer une exception.
Scala
val action = new TestAction() with LogAction with RetryAction;
action.doAction
En gros, on instancie une action avec le LogAction et RetryAction comme traits associés (with). a l’exécution, ça donne:
Try Action <-Aspect retry Before Action <-Aspect log Real Action <-Action réelle Retry Action <-Aspect retry Before Action <-Aspect log Real Action <-Action réelle Failed retry <-Aspect retry
Wow ! Sans Spring, sans AspectJ, sans reflection, sans weaving, sans rien ! Juste le langage Scala !
Lazy Fetch
Je passe maitnenant à une autre fonctionnalité Scala: le chargement déféré (lazy), une fonctionnalité très prisé par les ORMs (Hibernate, etc.).
L'implémenter en Java nécessite de passer par une bibliothèque de reflection (cglib, javassist, etc.) et le passage par des proxies.
En Scala, ça revient à ajouter le mot lazy à la défnition du champ.
Par exemple, si on a deux classes Person et School:
classe School: un somple POSO (POJO, mais à la sauce Scala)
Scala
case class School(id: Int, name: String)
Et un DAO ficitif :
Scala
object SchoolDb {
private val schools = List(School(1, "ensi"), School(2, "ipest"))
def school(id: Int) = {
println("getSchool")
schools.find(p=>p.id==id).get
}
}
Ne faites pas attention aux détails (closures, liste, etc.).
en gros, etant donné un identifiant, la méthode school retourne l'objet School qui a cet identifiant, mais aussi affiche un message getSchool.
Voici maintenant person:
Scala
case class Person(id: Int, name: String, schoolId: Int){
lazy val school : School = SchoolDb.school(schoolId)
}
Remarquez le lazy avant le chmp school ainsi que l'appele à la methode SchoolDb.school
Scala
val p = Person(1, "djo", 2);
println("...")
println(p.school)
println(p.school)
Ce qui affiche à la console:
... <-méthode SchoolDb.school non appelée jusque là getSchool <- méthode SchoolDb.school appelé suite au premier accès au champ person.school School(2,ipest) <- affichage du champ person.school School(2,ipest) <- affichage du champ person.school mais sans appel de SchoolDb.school
Voilou !
Je posterais plus tard un autr billet montrant une autre fonctionnalité super-puissante de Scala qui est le pattern-matching.
@Zeth636:
« je ne suis pas expert en php mais l’objet c’est en php5 … »
Il y à un semblant d’objet en PHP4
@Zeth636:
« ce n’est pas p.father mais p.school je pense que tu souhaite faire. »
Tout à fait ! Bien vu !
« peut etre est-ce la mise en relation avec hibernate qui emebete, lazy semble simplement faire l’appel pour avoir la valeur que lors de son acces ce qui est une chose interessetante car pour faire de meme en java cela passe automatiquement par la mise en place de getter/setter. »
Plus encore un champ boolean qui permet de savoir si on a déjà initialisé la variable lazy ou pas
« quelle sont les relations entre java et scala peut on avoir les librairies integrer du scala dans un projet java et inversement. »
Scala supporte totalement les APIs Java, càd qu’on peut utiliser des objets Java telquels, on peut hériter d’une classe Java et on peut implémenter des interfaces Java.
Le code généré tourne sur la JVM.
L’autre sens ne marche pas je crains: on peut pas étendre/utiliser des classe Scala depuis Java.
je ne suis pas expert en php mais l’objet c’est en php5 …
ensuite je suis surement trop jeune mais pascal je me demande si il existe un rapport plus que celui de tout language de programmation.
ensuite pour se qui est de l’article lui-même je le trouve tres interessant. On y trouve de bonnes choses, quelques petit mot clés simplifient bien la vie et le nombre de ligne de code (et d’erreurs potentiel).
l’exemple :
Scala
val p = Person(1, « djo », 2);
println(« … »)
println(p.father)
println(p.father)
ce n’est pas p.father mais p.school je pense que tu souhaite faire.
peut etre est-ce la mise en relation avec hibernate qui emebete, lazy semble simplement faire l’appel pour avoir la valeur que lors de son acces ce qui est une chose interessetante car pour faire de meme en java cela passe automatiquement par la mise en place de getter/setter.
sinon petite question que tu as peut etre repondu dans l’autre post mais quelle sont les relations entre java et scala peut on avoir les librairies integrer du scala dans un projet java et inversement.
Personnellement, ça ne me donne pas vraiment envie de jeter un oeil sur Scala. Une syntaxe à la PHP4 objet, Pascal et une utilité que j’ai du mal à saisir.
Peut-être ne suis-je simplement pas assez Elite pour ce truc là..
Je préfère continuer à découvrir/jouer avec Spring Hibernate & Co