Scala ajoute les macros au langage
L’équipe derrière Scala ajoute une version expérimentale des macros à la version 2.10 de Scala. Les macros de Scala fournissent une forme avancée de méta-programmation à la compilation. Le site des macros Scala avance :
Les macros simplifient significativement l’analyse et la génération de code, qui en font un outil de choix pour de nombreux cas d’usages. Ces problématiques qui impliquaient traditionnellement d’écrire du code superflu et difficile à maintenir peuvent maintenant être abordées de manière concise et maintenable. Par conséquent, nous pensons que les macros sont un atout précieux pour le langage de programmation Scala.
Les macros permettent aux développeurs de créer des méthodes dont l’implémentation est une transformation de l’arbre syntaxique. Il s’agit de méthodes définies de manière standard qui sont transformées de manière transparente à la compilation. Un exemple simple avec la méthode assert :
import scala.reflect.makro.Context
import language.experimental.macros
object Asserts {
def assert(cond: Boolean, msg: Any) = macro Asserts.assertImpl
def raise(msg: Any) = throw new AssertionError(msg)
def assertImpl(c: Context)(cond: c.Expr[Boolean], msg: c.Expr[Any]): c.Expr[Unit] =
if(assertionsEnabled) c.reify(if(!cond.splice) raise(msg.splice))
else c.reify(())
}
La macro assert apparait ici comme une méthode normale. Son implémentation utilise le mot clé macro pour déléguer le travail à une extension du compilateur assertImpl. Cette extension prend en paramètres le contexte courant de compilation ainsi que les arguments de la méthode assert passés sous forme d’arbres syntaxiques (Expr). Ces arbres syntaxiques sont alors utilisés pour générer un nouvel arbre syntaxique qui sera inséré à l’emplacement où est invoquée la méthode assert.
Pour la macro assert, une invocation de assert(x != null, "X is null") remplira la variable cond avec l’arbre syntaxique correspondant à x != null. La variable msg avec l’arbre syntaxique correspondant à "X is null". L’appel à reify permet de générer un nouvel arbre syntaxique correspondant à if(x != null) Asserts.raise("X is null") ou (). Ce nouvel arbre syntaxique généré remplace alors l’appel original assert(x != null, "X is null")
Le mot clé reify et le système de macros auto-nettoyées sont définis plus en détails dans la proposition SIP-16.
L’ajout des macros est considéré comme douteux par certains. Dans un article de blog intitulé Scala Macros: Oh God Why?, Jay Kreps évoque :
Ce fût également ma réaction à la proposition des macros. Non pas à cause des macros en elles-mêmes, mais simplement parce que : est-ce réellement la fonctionnalité la plus critique à ajouter au langage ? »
Kreps énonce une liste de problèmes plus prioritaires sur lesquels il faudrait s’attarder, comme la vitesse de compilation, le support des IDE, la documentation, et la taille des binaires générés.
Kreps n’est pas le seul préoccupé par cette nouvelle fonctionnalité. Ivan Todoroski écrit sur la mailing list Scala:
Les macros Scala répondent de façon obscurément experte à un problème qu'on peine encore à trouver. Elles sont difficiles à écrire et débugger, même pour un développeur expérimenté, et vont probablement apporter au langage l’image de magie impénétrable trop complexe.
Ce à quoi Martin Odersky, créateur du langage Scala, répond:
L’intention des macros, et du langage Scala en général, est de simplifier les choses. Nous avons déjà réussi à remplacer du code existant par des macros, et nous espérons que d’autres fonctionnalités suivront. Par exemple, il y a une forte demande pour – en quelque sorte – supprimer le paramètre implicite dans "atomic { implicit transaction => ... }" et d’autres situations similaires. Avec les macros, la solution est évidente.
Le débat sur les macros s’est calmé et la communauté attend une version finale. Mais la version expérimentale n’empêche pas les plus aventureux de se faire la main, et plusieurs projets opensources exploitant la fonctionnalité ont vu le jour :
- Macrocosm – Une librairie expérimentant les macros sur des cas d'utilisation réels.
- Expecty – Une adaptation du système d’assertions du framework de tests Spock (Groovy).
- Slick – Une tentative de créer une librairie similaire à LINQ. Slick peut convertir une syntaxe Scala en requêtes de bases de données.
- ScalaMock – Une librairie de mock en Scala.
Une liste des autres nouveautés de Scala 2.10 est dressée dans la release note 2.10.0-M4 et inclue les fonctionnalités suivantes:
Alors que la date de la release finale de Scala 2.10 approche, l'équipe invite les développeurs à tester la dernière version milestone et à faire un retour. Vous pouvez télécharger la dernière version milestone ici.