Je profite d’un peu de temps entre 2 missions pour me former à Scala depuis quelques temps. J’ai vraiment beaucoup de plaisir à apprendre et à travailler avec ce nouveau langage. Proche de Java, il est pourtant bien différent, et vraiment intéressant comme nous allons le voir ensemble.
James Gosling, l’un des inventeurs de Java, a dit à propos de Scala la phrase suivante :
« If I were to pick a language to use today other than Java, it would be Scala »
Plus suprenant, James Strachan qui a initié le langage Groovy en 2004, a dit aussi à propos de Scala :
« I can honestly say if someone had shown me the Programming in Scala book by by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I’d probably have never created Groovy. »
Le langage a été initié en 2003. Scala (pour Scalable Language) a été pensé pour la programmation multi-threads, avec un niveau de qualité assez impressionnant. J’aime ce langage car au final, ce sera toujours du bytecode dans une machine virtuelle Java.
C’est un langage orienté objet avec une teinte de programmation fonctionnelle. Créé en 2003 par Martin Odersky, Scala est supporté par l’EPFL (Ecole Polytechnique Fédérale de Lausanne). Typé statiquement, il propose par exemple une inférence de type très puissante, qui rend la programmation Java « old-school » dès lors que l’on débute en Scala.
Scala est concis
Le langage est très concis. Prenons par exemple un BVOJTP (Bon Vieil Objet Java Tout Pourri) et voyons ce que cela donne dans sa version Scala. Je prends par exemple un simple Bean « Person » avec quelques attributs.
La version Java
public class PersonInJava { private String firstName; private String lastName; private Date dateOfBirth; public PersonInJava(String firstName, String lastName, Date dateOfBirth) { this.firstName = firstName; this.lastName = lastName; this.dateOfBirth = dateOfBirth; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Date getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; } }
La version Scala :
class PersonInScala(val firstName: String, val lastName: String, val dateOfBirth: Date)
Et oui… par défaut il n’est pas nécessaire de déclarer les getters/setters, ni de constructeur par exemple.
Inférence de types
Scala est capable de deviner les types associés à des expressions automatiquement (voir la définition del’inférence de types). Cela permet de conserver un type fort en interne, tout en allégeant le code source.
var year: Int = 2010 var anotherYear = 2010 var helloBuddy = "Salut !" var builder = new StringBuilder("Bonjour") println(builder.getClass())
La première variable est définie comme étant de type Int. Remarquez ensuite que la variable anotherYear est définie sans spécifier de type. Scala infère le type en Int automatiquement grâce à la valeur que nous avons assignée à cette variable. Ce type est définitif, il s’agit bien d’un type statique.
Si par exemple j’essaye d’affecter une String un peu plus tard à ma variable anotherYear alors Scala me signale à la compilation qu’il y a un souci :
var anotherYear=2010 anotherYear="This is a String" (je compile le code...) !!! discarding
Pour revenir un peu plus haut, la variable helloBuddy est inférée en java.lang.String automatiquement, et la variable builder en StringBuilder. Dans la pratique, pour un développeur Java il n’y a pas grand chose à faire. Il reste possible de typer ses variables, mais cela ne devient plus indispensable. Enfin la vérification à la compilation nous épargne les soucis de transtypage à la Java et certainement quelques soucis comme avec un langage dynamique.
Programmation fonctionnelle
Je ne vous donnerai qu’un aperçu car c’est un sujet vaste. En Scala il est possible de créer des fonctions à l’intérieur de fonctions, de passer des méthodes en paramètres à d’autres méthodes, bref les fonctions en Scala sont des Objets à part entière. Nous retrouvons la notion de pointeur de fonctions en quelques sortes.
La programmation fonctionnelle sera présenté en Avril au Paris JUG, ainsi que Scala d’ailleurs. Cela vous donnera l’occasion de voir un peu ce que cela peut vous apporter en tant que vieux Java-iste.
Prenons un exemple tiré du livre « Programming Scala » écrit par V.Subramaniam. Ecrivez une fonction qui effectue la somme d’une suite de nombre sur une plage passée en argument. Voici la version Java :
public int sum(int number) { int result = 0; for(int i = 1; i < = number; i++) { result += i; } return result; }
Comment feriez-vous si je vous demande maintenant de faire l'addition des nombres pairs uniquement ? En Java vous feriez une copie de cette méthode, pour en créer une nouvelle, avec votre algo. En Scala, il est possible de passer une méthode en paramètre. Nous allons donc extraire la logique de la sélection des valeurs, et la définir à l'extérieur.
Des fonctions qui prennent en paramètre d'autres fonctions sont appelées "higher-order function". En Scala vous pouvez créer des fonctions à l'intérieur d'autres fonctions, les passer en paramètre et les assigner à des références.
Voici une version en Scala pour itérer sur une plage de valeur. Pour chaque valeur nous allons appeler la fonction référencée par codeBlock qui retourne un Int.
def totalResultOverRange(number: Int, codeBlock: Int => Int) : Int = { var result = 0 for (i < - 1 to number) { result += codeBlock(i) } result }
Donc pour effectuer la somme de valeur, nous pourrons appeler la fonction en spécifiant une fonction d'addition très simple :
// Sum up to 10 println(totalResultOverRange(11, i => i))
Le premier argument, 11, est la limite supérieure de notre série. Le second argument est une fonction anonyme qui prend en argument un type et qui le retourne sans modification. Notez qu’ici nous ne précisons pas le type Int, il sera inféré par Scala au moment voulu en examinant la signature de la méthode totalResultOverRange.
Si je vous demande maintenant d’effectuer la somme des nombres pairs uniquement dans la série, voici comment nous écrirons en Scala cet appel:
println(totalResultOverRange(11, i => if (i % 2 == 0) i else 0))
Si le modulo 2 du compteur courant est égal à 0, alors nous retournons i pour l’additionner, sinon 0.
Il est bien entendu possible de définir des Closures. Ici nous définissons une variable closure qui sera un pointeur vers une méthode.
def loopThrough(number: Int)(closure: Int => Unit) { for (i < - 1 to number) { closure(i) } }
Voici un exemple d'utilisation :
var result = 0 val addIt = { value:Int => result += value }
Dans ces quelques lignes ci-dessus je crée une variable « addIt » qui est un bout de code pour effectuer l’accumulation de deux valeurs. Notez que la variable result n’est pas définie dans ce bloc ni comme paramètre. En fait cette variable est branchée à la variable result en dehors du bloc de code. Je pense qu’un exemple sera plus parlant pour expliquer cette subtilité :
var result = 0 val addIt = { value:Int => result += value } loopThrough(10) { addIt } println("Total of values from 1 to 10 is " + result) result = 0 loopThrough(5) { addIt } println("Total of values from 1 to 5 is " + result) // Execution Total of values from 1 to 10 is 55 Total of values from 1 to 5 is 15
Comprenez qu’une Closure est un bloc de code qui s’exécute dans un contexte, tout en étant capable de modifier des variables externes. Lorsque j’appelle la méthode loopThrough() en spécifiant une closure, la variable result est vue comme une variable globale. Lorsque je remet à 0 la variable, la closure le « voit » aussi et débute à nouveau l’itération de 0. Il est possible aussi de n’utiliser que des variables locales pour ne pas avoir cet effet bien entendu. C’est la vraie notion de Closure, où les variables d’une portée plus importante sont vues localement au sein de la fonction.
Conclusion de cette première partie
Scala est donc un langage fortement typé, capable de faire de l’inférence de types, avec une manipulation des fonctions très puissante, et la possibilité d’utiliser des Closures.
En Scala, tout est objet. Un nombre comme « 2 » est un objet sur lequel il est possible d’appeler une fonction. Les fonctions sont des objets, que vous passez en paramètre, afin d’exécuter des traitements fonctionnels.
Nous verrons la prochaine fois les Traits et les Collections, puis nous parlerons de programmation concurrente avec les Actors.
Je vous recommande la lecture de « Programming Scala » écrit par V.Subramaniam. Ce livre a été pensé pour des développeurs Java qui souhaitent apprendre rapidement Scala.
Je pense qu’il ne faut que quelques semaines pour être opérationnel. Il y a le risque de faire du « Java-like » avec Scala, comme nous faisions du C à la place du C++. Mais je pense cependant que vu la maturité du langage, la quantité de documentations et de livres disponibles, nous pouvons éviter de tomber dans ce piège.
Alexandre Bertails a préparé la version Scala de mon article sur le XML et Groovy. Vous verrez différentes versions d’ici quelques jours, le temps de terminer les 2 autres articles sur Scala.
Bon, je pose le crayon deux secondes, j’ai besoin de toute votre attention. Eteignez Twitter, fermez Gmail, écoutez-moi : vous allez apprendre Scala. C’est un ordre. Si vous ne voulez pas être sur le côté de la route lorsque les petits jeunes roulant en Scala Bac+5 passerons à côté de vous, bougez-vous. Achetez un livre, prenez le temps de vous former à nouveau.
Etre bon en Spring, Hibernate, GWT c’est bien. Maintenant ce qui va faire la différence, ce sera la capacité à proposer sur le marché d’autres langages pour répondre aux clients. N’oubliez pas ce que j’ai dit au début : Scala c’est du bytecode qui tourne dans une JVM. Donc pas d’excuses, vous me ferez 2 séries d’abdos, et ensuite vous filez en formation Scala.
Non mais !
0 no like
Apprendre Scala pour les vieux Javaistes.
Ca me fait penser à de vieux RPGistes ou Cistes qui ont vu arriver une génération de barbares qui voulaient ré-écrire toutes les applications de la maison en … Java.
Il aura fallu, 5 à 10 ans pour que cela devienne une réalité et que la technologie des jeunes barbares devienne parole d’évangile. 5/10 ans d’efforts constants.
Nicolas a raison de dire qu’il faut toujours être en mouvement, la techno phare d’aujourd’hui pouvant être décriée par les petits jeunes qui fatalement arriveront un jour à vos portes.
Eux aussi feront du lobbying, amèneront des arguments recevables et n’apprécieront pas plus que nous un certain conservatisme.
Par honnêteté intellectuelle, on se doit de rester ouvert à de nouveaux outils et méthodes et pour cela, il faut se remettre en question régulièrement et ça passe, aussi, par l’apprentissage de nouveaux langages, qu’ils percent ou non.
Bon lundi à tous les vieux Javaistes 🙂
Bonjour,
Je ne suis pas sûr qu’apprendre Scala soit absolument nécessaire pour rester employable face au d’jeuns dans les années à venir.
Cela serait le cas si Scala avait le potentiel de détroner Java. Mais est ce la cas ? que cherche les entreprises ? Pourquoi Java a t’il été préféré aux anciens langages qu’ils soient objets ou fonctionels ?
A mon humble avis, c’est simplement que Java est accessible au plus grand nombre, il peut être appris à l’école. Pas besoin d’être un geek pour trouver du boulot en Java. Il faut juste comprendre ce qu’est la POO (c’est déjà une grosse barrière).
Scala introduit de (quasi) nouveaux concepts où plutôt les impose, là ou en Java on peut toujours se débrouiller sans : l’aspect avec les traits, la programmation fonctionnelle, les closures, les objets immutables, les actors, les singletons. Autant de barrières pour celui qui a choisi l’informatique « par défaut ».
Sans compter que Scala est moins verbeux. Je ne suis pas certain qu’un langage moins verbeux soit plus facile à apprendre.. (à maintenir sans doute mais à apprendre… j’en doute.)
Pour tout cela, je pense que Scala restera un langage à la marge. Il reste toutefois intéressant de se former dessus car il peut être utile dans certaines situations (notament l’écriture d’algorithmes récursifs qui planteront en Java mais ne planteront pas en Scala) et son apprentissage nous rend simplement meilleurs en Java.
Je suis bien d’accord avec toi. Comme tu citais récemment ce livre, je me permets aussi de le faire.
http://www.amazon.com/Programming-Scala-Multi-Core-Complexity-
Programmers/dp/193435631X
Aujourd’hui les cores dans le processeurs sont partout mais peu exploité. La programmation multithread n’est pas triviale du tout même avec des api géniales comme celle de Doug Lea.
A mon humble avis, Scala apporte vraiment un plus à ce niveau et il ne faut pas râter de se former à ce nouveau langage et cette nouvelle approche.
Après on peut toujours reprocher à Scala de ne pas avoir quelques fonctions propres aux langages ML mais c’est pas très grave selon moi. L’API Actor est une tuerie qui mérite à elle seule de s’intéresser au langage.
Tu as bien raison de dire que le danger c’est de refaire en Scala du javalike.
Super article comme d’habitude. Ce blog est trop plein de bonnes choses 🙂
Je pense qu’au delà de l’inférence de type, chaque programmeur devrait lire Structure and Interpretation of Computer Programs de Hal Abelson and Gerald Jay Sussman ( http://mitpress.mit.edu/sicp/full-text/book/book.html ) histoire de bien comprendre la programmation fonctionnelle, ou même se faire plaisir et comprendre les continuations avec The Scheme Programming Language de R. Kent Dybvig ( http://www.scheme.com/tspl3/ ).
Quand on comprend vraiment ce que sont les clotures et les continuations on a un bagage pour la vie. Ce n’est pas forcément plus important que de comprendre les threads ou les macros (les vraies, pas CPP), mais tout aussi important je pense.
Enfin, Scala est peut-être un (relativement) nouveau language mais ce que tu montres (clotures et inférence de type) est légèrement vieux (1958-60 pour les deux).
Moi je trouve ça très bien ces features, et le fait que le monde procédural/objet les importent enfin du monde fonctionnel c’est super, je ne peux que m’en réjouir. Mais par contre c’est pas nouveau 😉
Après je ne suis pas expert en Scala, il y a sans doute de vraies nouveautés.
« Si vous ne voulez pas être sur le côté de la route lorsque les petits jeunes roulant en Scala Bac+5 passerons à côté de vous, bougez-vous. Achetez un livre, prenez le temps de vous former à nouveau. »
Sans vouloir jouer au « vieux con », je crois qu’on m’a fait le même coup avec Ruby On Rails il y a quelques années 🙂
Bonjour,
Je suis aussi en train de lire « Programming in Scala » et je dois dire que je suis un peu inquiet de savoir comment le langage peut rester lisible entre les programmeurs. L’auteur commence toujours par « voila comment un developpeur java ferait » et termine par « mais c’est pas comme ca qu’il faut faire, il vaut mieux faire ca de maniere fonctionnelle ».
Faire de maniere fonctionnelle va etre quelque chose d’assez dure pour tout programmeur java.
Cela veut dire qu’il existe multiple facons de faire la meme chose, ce qui en soit est tres bien. Par contre je suis un peu inquiet quand a la consistance du code (fonctionnel vs procedural). Aussi si quelqu’un reprends le code functionel et fait du procedural, cela peut peut-etre poser probleme.
Mais peut-etre que je m’inquiete pour rien? Qu’en penses-tu?
Bonjour,
Juste une remarque:
La version Scala du javabean est :
class PersonInScala(var firstName: String, var lastName: String, var dateOfBirth: Date)
Ce qui me permet de faire remarquer qu’en scala on doit obligatoirement specifier si une variable est mutable ou non (ce qui est un bon point pour les fans du mot cle final en java). Du coup ta version est un objet immutable (et c’est bien).
Ce qui m’amene aussi a me demander quel est l’utilite d’un setter public sur un champs private en java …
Merci pour tes articles.
@NicolasLeRoux (Play! Framework) > je travaille sur une partie du noyau de JBoss Tohu écrit en Scala justement. D’où mon envie de me former il y a quelques temps. Et je dois reconnaître que j’ai pas mal de mal à lire et à travailler efficacement en Scala pour l’instant.
Moi qui aime les analogies, en voici une : Apprendre Groovy c’est comme apprendre l’Espagnol lorsque tu es Français. La grammaire est un peu dure mais c’est facile. Scala c’est plus apprendre l’Allemand (ou le Hollandais pour toi). Il y a moins de racines communes à notre langue Française, comme Java.
Le souci de la programmation fonctionnelle et que cela ne représente que 8% des langages enseignés et qu’en effet, c’est très minoritaire sur le marché. Cependant nous parlons du passé, avant l’arrivé de Scala qui tourne sur la JVM, et adresse particulièrement bien les problèmes de programmation concurrente, bien mieux que Java. Donc je pense que Scala sera particulièrement adapté à certains problèmes, et qu’il ne remplacera pas Java.
Par exemple, j’ai été assez déçu par Lift! présenté à Devoxx, par rapport à Grails ou Play!
Nicolas
@jprudent : en effet il faudre que j’explique la différence entre val et var en Scala la prochaine fois
Ce n’est pas Scala, Ruby ou Groovy qui compte dans cette phase d’apprentissage obligatoire.
C’est le fait de sortir de nos habitudes de vieux Javaistes pour ne pas passer pour les conservateurs de demain.
C’est peut être cela le message de Nicolas, remettre en question certaines habitudes et évidence, avant que cela ne soit des petits jeunes développant en Scala ou autre, qui ne l’imposent à marche forcée.
Bonjour,
Dans cette première partie, je ne vois pas l’apport de Scala vis à vis de groovy, peut être par la suite…
Il serait intéressant d’ajouter au comparatif groovy (en tout cas cela m’intéresserait).
Merci pour tes articles, j’attends la suite avec impatience.
En revanche, Kirk Pepperdine, questionné à propos de sa préférence parmi les langages dynamiques JVM existants, choisirait JRuby. Entendu lors de la session privée avec Kirk organisée chez Xebia le 20 janvier 2010.
Juste un pavé dans la mare … 🙂
Nicolas Leroux
« Par contre je suis un peu inquiet quand a la consistance du code (fonctionnel vs procedural) »
Sans compter que Scala propose la surcharge des opérateurs et les noms de méthodes courts. L’exemple de base en Scala étant « (0/:l)(_+_) » , qui renvoie la somme des éléments contenus dans ‘l’. A l’écriture c’est très sympa, à la maintenance un poil moins.
@Aurélien MAURY
Par « dynamiques » tu sous entends « typage dynamique » ?
Scala est statiquement typé (inférence != dynamique) donc le pavé s’enfonce sans éclat 😉
@jprudent Tu t’es un peu embrouillé sur ton histoire d’immutabilité. C’est normal, c’est plus compliqué que ça en a l’air 🙂
En effet, la version de Nicolas est bien immutable. En effet, utiliser des ‘var’ ne va pas aider. Par contre, tu ne peux pas « specifier si une variable est mutable ou non ». La sémantique du mot clé ‘var’ est de préciser si on peut affecter une nouvelle valeur à la variable en question. Mais rien ne t’interdit, si l’objet est mutable, de le modifier. Donc comment savoir si un objet est réellement immutable ? Lis bien la doc de l’implémentation choisie. C’est toute la différence entre ‘scala.collection.mutable’ et ‘scala.collection.immutable’.
C’est une des faiblesses de Scala : l’immutabilité ne transparait dans le typage. 1. Ça aiderait le programmeur si pour une raison quelconque il voudrait s’assurer qu’il a bien quelque chose d’immutable in fine 2. Ça permettrait de faire des optimisations à la compilation. Mais ce n’est en fait pas simple car Scala repose sur la _liaison dynamique_ (c’est pas définition la différence fondamentale entre l’OO et la Programmation Fonctionnelle pure). C’est ce qui permet de dire : à tel endroit, j’ai besoin d’un objet de tel type (ou sous-type), que je donnerai plus tard. Or cet objet peut lui-même être mutable d’où le problème 🙂 Je pense quand même que le compilateur actuel doit savoir reconnaître les cas simples de réelle immutabilité.
Je pense que l’exemple donné pour sommer les nombre pairs est erroné et il faudrait remplacer la ligne
println(totalResultOverRange(11, i => if (i % 2 == 0) 1 else 0))
Par
println(totalResultOverRange(11, i => if (i % 2 == 0) i else 0))
Le code est donné à titre d’exemple, mais pour information une manière « plus scala » ce ferait en utilisant les itérateurs interne:
Somme sur une plage de valeurs :
(1 to 11).foldLeft(0)((a,b) => a+b)
En ne prenant que les nombres pairs :
(1 to 11).filter(x => x%2 == 0).foldLeft(0)((a,b) => a+b)
Scala est un langage très intéressant pour un développeur avancé, aucun doute là-dessus.
J’ai cependant de gros doutes sur sa capacité à etre utilisable auprès de développeurs lambda. Scala est un langage pour le moins dense, et il n’est pas toujours facile de relire le code, surtout lorsque du fonctionnel est utilisé. Scala a un authentique risque de se C++-iser.
Scala risque donc de rester confiné aux projets pointus où les compétences des équipes sont de très bon niveau. Pour le reste, Scala a peut être une chance dans des projets classiques si on se limite à l’utiliser dans un sous-ensemble objet pour sa syntaxe plus compacte …
Je n’aime pas trop ces réflexions sur le « développeur lambda ».
C’est vrai que j’ai vu des gens galérer à écrire une boucle, mais je n’aime pas trop l’idée d’un DSI dans son bureau qui se dit « mes gars sont trop nuls pour apprendre Scala ». Je pense qu’à peu près tout le monde peut tout apprendre avec le temps, même si certain apprennent moins vite et/ou ont plus de retard.
On peut aussi avoir plusieurs niveaux de programmation, dans un application/SI polyglotte : un niveau « facile » en java ou autre langage simple (à inventer ?) et un niveau « avancé » en Scala pour le code complexe où ce langage sera utile.
Je pense que le langage est populaire dans notre communauté parce que nous sommes très attaché au typage statique fort. Groovy et Ruby nous troublent plus.
Pour ce qui est de la lisibilité, on peut écrire du brun dans n’importe quel langage (bon c’est plus facile en PHP ou Perl qu’en java certes) et je m’attends à l’apparition d’équivalents de PMD et checkstyle pour Scala assez rapidement. Il y a aussi une phase d’apprentissage : «(0/:l)(_+_)» est relativement clair quand on connait Scala.
Je pense que le succès de Scala, si succès il y a, viendra plutôt par la qualité des frameworks et apis qui seront proposés que par la syntaxe du langage lui même car celle ci est assez difficile d’accès pour un débutant…
Est-ce que Scala au travers de lift par exemple apporte un vrai plus de le développement web en terme de productivité et de maintenabilité ? Il ne faut pas oublier que ce qui nourri les développeurs c’est essentiellement du web et de l’informatique de gestion !
@Jean-Michel Bea à signaler, pour l’utilisation des itérateurs internes, que les paramètres nommés peuvent être remplacés par le wild card « _ » (paramètres nommés que si nécessaire). Les scalaistes en sont friands et on se retrouve donc face à un code qui ressemble plutôt à ça :
(1 to 11).filter(_%2==0).reduceLeft(_+_)
Le langage en lui même est une chose, mais il faut ensuite pouvoir l’utiliser pour développer une application complète (persistence, framework MVC, …). J’ai cru comprendre qu’un des atouts de scala c’est qu’il permet d’utiliser des librairies java. Est-ce vraiment le cas ? On trouve pas mal de tutos et d’exemples sur la toile mettant en évidence les concepts du langage, mais je n’ai pas vraiment trouvé d’exemple d’applis scala utilisant l’API JPA (2.0, tant qu’à faire). Le fait q\’un nouveau framework MVC en scala (Lift) ait vu le jour n’est pas vraiment rassurant. On ne peut dont pas réutiliser un framework java existant (et surtout éprouvé) ? S’il faut ré-implémenter des équivalents pour toutes les librairies existantes dans le monde java, on retombe dans le même travers que Ruby… Et qui fait la force de Groovy. Même si je ne crois pas à l’avenir des langages dynamiques (qui resteront toujours 10 à 20 fois plus lents qu’un langage fortement typé et qui ne pourront jamais être aussi bien outillés dans un IDE -justement parce qu’ils sont dynamiques-).
Je ne comprend pas, en quoi c\’est mieux de ne pas avoir de getter/setter ? Autant, si on le fait à la flex ou on définit des droits d\’écriture et de lecture sur les méthodes, ou à la Eiffel qui n\’autorise jamais l\’écriture, et qui autorise la lecture uniquement aux cibles demandées.
Je n\’ai pas encore regardé ça de plus près, mais le peu qui y est fait se poser des questions…
@Rod
Utiliser JPA en scala est tout a fait possible. Il faut juste prendre en compte les particularités de JPA, variables non finales (adieu les val bonjour les var), utiliser les collections java et non scala, etc.
Lift a d’ailleurs un module JPA (preuve que ça marche) voir ici
Le framework play a un module scala voir ici
L’annotation @BeanProperty permet d’être compatible avec bien des frameworks marchant sur la convention getter/setter.
Désolé j’ai un peu raté mes balise 🙁
Message de Nicolas : c’est réparé 😉