SlideShare uma empresa Scribd logo
1 de 20
Baixar para ler offline
Mort au Boilerplate
avec
Scala-meta
Me
Damien Gouyette
Freelance
Utilise des macros depuis 2012
En produit depuis 2014
Objectifs
Comprendre : les bases de Scala-meta
Encourager : à lui donner un galop d’essai
=> Générer votre boilerplate <=
Un peu de vocabulaire
Abstract Syntax Tree (AST)
Ce qui représente le programme.
On (d)écrit cet AST en utilisant une
arborescence de symbole
Tout est SYMBOLE en Scala
Tout ce que l’on peut définir ou donner un nom
En savoir + : symbols-trees-types
Symbole Mot clef ou entité
Class Classe
Term val, var, def, object...
Lit litéral (String, Int, etc…)
Symbole : Defn.Class
Le symbole porte toutes les informations de
l’entité à laquelle il fait référence
Defn.Class(
mods :Seq[scala.meta.Mod], // modifiers (Private, Implicit, final, sealed…)
name : Type.Name, // nom du type
tparams :Seq[Type.Param], // Types paramétrant la classe
ctor :Ctor.Primary, // contructeur
templ :Template// body de la class
)
Qu’est ce qu’une macro ?
AST
Code
Des symboles pour décrire un AST qui génère du
code
Annotation vs def macros
//def macros avec scala-reflect
implicit val userWrites = Json.writes[User]
//macro par annotations (scala-meta)
@ShowMacro(constructorParams)
case class Name(firstName: String, lastName: String)
Utiliser des macros est facile
case class User(firstName : String, lastName : String)
object User {
//def macro
implicit val userWrites = Json.writes[User]
//génère le code suivant
implicit val userWrites = (
(__  "firstName").write[String] and
(__  "lastName").write[String] )
(unlift(User.unapply))
}
Mais les écrire…
defn match {
case q"class $className[..$classTypes] { ..$body }" =>
val types = classTypes.map(t => Type.Name(t.name.value))
val typesName: Seq[Name] = classTypes.map(t => Term.Name(t.name.value))
val result =
q"""
class $className[..$classTypes] {
..$body
..${
typesName.zipWithIndex.map { case (currentTypeName, y) =>
val unionXType2UnionXMethodName = Term.Name("toUnion" + y)
val currentType = Type.Name(currentTypeName.value)
val unionXType = Term.Name("Union" + classTypes.size)
val constructorArgs : Seq[Term.Arg] = for (x <- typesName.indices) yield q"""${argByXY(x, y)}"""
q"implicit def $unionXType2UnionXMethodName(t : $currentType) = $unionXType[..$types](..$constructorArgs)"
}
}
Quasiquote
Simplifier construction/déconstruction des symboles
q"""println("hello world")"""
Est équivalent à
Term(Term.Name("println"), Seq(Lit.String("hello world")))
Refcard quasiquotes
Résultat attendu
@Show
case class Name(firstName: String, lastName: String)
object Name {
def show(n : Name) : String =
"Name" + "(" + List("firstName" + "=" + n.firstName),
"lastName" + "=" + n.lastName).reduce(_ + "," + _) + ")"
}
Déconstruction de la class annotée
@ShowMacro //class annotée
case class Name(firstName: String, lastName: String)
---
class ShowMacro extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
// 1) version simple
case Defn.Class(mods, name, tparams, ctor, template)=>
// 2) avec companion
case Seq(Defn.Class(m, n, t, c, t), companion: Defn.Object)=>
//3) version simplifiée avec quasiquotes
case q"case class $name(..$lFields)"=>
Construction de l’AST
q"""${cls.name.value} + "(" + //Name + (
List(..${ctor.paramss.flatMap(_.map(pp => q"""${pp.name.syntax} //List("name" + "=" +a.name,
+ "=" +a.${Term.Name(pp.name.value)}""" ))}) //, "age" + "=" + a.age )
.reduce(_ + "," + _) + ")" } }""" //.reduce(_ + "," + _) + ")"
AST attendu
case class Name(firstName: String, lastName: String)
object Name {
def show(n : Name) : String = List(
"Name" + "(" + List("firstName" + "=" + n.firstName),
"lastName" + "=" + n.lastName).reduce(_ + "," + _)
}
Gist
Code complet
package io.github.hamsters
import scala.collection.immutable.Seq
import scala.meta._
class ShowMacro extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case cls @ Defn.Class(_, _, _, ctor, _) =>
val show =q"""
implicit def showable = new io.github.hamsters.Showable[${cls.name}] { override def format(a: ${cls.name}) ={
import io.github.hamsters.ShowableSyntax._
${Lit.String(cls.name.value)}+ "(" + List(..${ctor.paramss.flatMap(_.map(pp => q"""${pp.name.syntax} + "=" +
Show.show(a.${Term.Name(pp.name.value)})""" ))}).reduce(_ + "," + _) + ")" } }"""
val companion = q"object ${Term.Name(cls.name.value)} { $show }"
val res = Term.Block(Seq(cls, companion))
//abort(res.syntax)
res
case _ => abort(defn.pos, "Invalid annottee - you can only use @Show on case classes")
}
}
}
Compilation, dans un module séparé
+ project
- macros
+ build.sbt
lazy val macros = project.settings(
libraryDependencies += "org.scalameta" %% "scalameta" %
"1.8.0" % Provided)
lazy val app = project.dependsOn(macros)
sbt clean && sbt compile
En savoir +
Hamster : Librairie Scala compatible avec les
débutants en programmation fonctionnelle (plein
de macros dedans)
AST Explorer : outil de visualisation
Refcard quasiquotes
Introduction pratique aux macros scala
Questions ?

Mais conteúdo relacionado

Mais procurados

Theme 9(bis)
Theme 9(bis)Theme 9(bis)
Theme 9(bis)
salmazen
 

Mais procurados (15)

Cpp2 : classes et objets
Cpp2 : classes et objetsCpp2 : classes et objets
Cpp2 : classes et objets
 
Les listes en Python
Les listes en PythonLes listes en Python
Les listes en Python
 
UML OCL : Liaison avecUML -- 24
UML OCL : Liaison avecUML -- 24UML OCL : Liaison avecUML -- 24
UML OCL : Liaison avecUML -- 24
 
Introduction Clojure - Geneva JUG - Octobre 2012
Introduction Clojure - Geneva JUG - Octobre 2012Introduction Clojure - Geneva JUG - Octobre 2012
Introduction Clojure - Geneva JUG - Octobre 2012
 
Structure de données en PHP
Structure de données en PHPStructure de données en PHP
Structure de données en PHP
 
Présentation de data.table
Présentation de data.tablePrésentation de data.table
Présentation de data.table
 
Csharp2 : classes et objets
Csharp2 : classes et objetsCsharp2 : classes et objets
Csharp2 : classes et objets
 
Js part2
Js part2Js part2
Js part2
 
Theme 9(bis)
Theme 9(bis)Theme 9(bis)
Theme 9(bis)
 
initiation au javascript
initiation au javascriptinitiation au javascript
initiation au javascript
 
Anatomie d'une typeclass
Anatomie d'une typeclassAnatomie d'une typeclass
Anatomie d'une typeclass
 
Formation Jquery
Formation JqueryFormation Jquery
Formation Jquery
 
Une Introduction à R
Une Introduction à RUne Introduction à R
Une Introduction à R
 
Marzouk collection-map
Marzouk collection-mapMarzouk collection-map
Marzouk collection-map
 
Theme 9
Theme 9Theme 9
Theme 9
 

Semelhante a Mort au boilerplate avec scala meta

Interface collectionsinter
Interface collectionsinterInterface collectionsinter
Interface collectionsinter
RYMAA
 
fdocuments.fr_chap-03-poo-en-java-partie1.pptx
fdocuments.fr_chap-03-poo-en-java-partie1.pptxfdocuments.fr_chap-03-poo-en-java-partie1.pptx
fdocuments.fr_chap-03-poo-en-java-partie1.pptx
TarikElMahtouchi1
 
Introduction au langage Ruby
Introduction au langage RubyIntroduction au langage Ruby
Introduction au langage Ruby
Julien Blin
 

Semelhante a Mort au boilerplate avec scala meta (20)

RCarte_Commandes-R.pdf
RCarte_Commandes-R.pdfRCarte_Commandes-R.pdf
RCarte_Commandes-R.pdf
 
Introduction à scala
Introduction à scalaIntroduction à scala
Introduction à scala
 
Interface collectionsinter
Interface collectionsinterInterface collectionsinter
Interface collectionsinter
 
Change mind about JS
Change mind about JSChange mind about JS
Change mind about JS
 
Héritage et Polymorphisme .pdf
Héritage et Polymorphisme .pdfHéritage et Polymorphisme .pdf
Héritage et Polymorphisme .pdf
 
Scala IO 2017 : Probabilités fonctionnelles
Scala IO 2017 : Probabilités fonctionnellesScala IO 2017 : Probabilités fonctionnelles
Scala IO 2017 : Probabilités fonctionnelles
 
Héritage et redéfinition de méthode
Héritage et redéfinition de méthodeHéritage et redéfinition de méthode
Héritage et redéfinition de méthode
 
Spark dataframe
Spark dataframeSpark dataframe
Spark dataframe
 
22-reflection.pdf
22-reflection.pdf22-reflection.pdf
22-reflection.pdf
 
Python avancé : Classe et objet
Python avancé : Classe et objetPython avancé : Classe et objet
Python avancé : Classe et objet
 
fdocuments.fr_chap-03-poo-en-java-partie1.pptx
fdocuments.fr_chap-03-poo-en-java-partie1.pptxfdocuments.fr_chap-03-poo-en-java-partie1.pptx
fdocuments.fr_chap-03-poo-en-java-partie1.pptx
 
POO
POOPOO
POO
 
UML OCL : Cheat Sheet - 10
UML OCL : Cheat Sheet - 10UML OCL : Cheat Sheet - 10
UML OCL : Cheat Sheet - 10
 
Introduction au langage Ruby
Introduction au langage RubyIntroduction au langage Ruby
Introduction au langage Ruby
 
Présentation Scala
Présentation ScalaPrésentation Scala
Présentation Scala
 
Chapitre5: Classes et objets
Chapitre5: Classes et objetsChapitre5: Classes et objets
Chapitre5: Classes et objets
 
generation_code.pdf
generation_code.pdfgeneration_code.pdf
generation_code.pdf
 
Chp6 - De UML vers C++
Chp6 - De UML vers C++Chp6 - De UML vers C++
Chp6 - De UML vers C++
 
Présentation nouveauté java7
Présentation nouveauté java7Présentation nouveauté java7
Présentation nouveauté java7
 
Java 8 : Un ch'ti peu de lambda
Java 8 : Un ch'ti peu de lambdaJava 8 : Un ch'ti peu de lambda
Java 8 : Un ch'ti peu de lambda
 

Mort au boilerplate avec scala meta

  • 2. Me Damien Gouyette Freelance Utilise des macros depuis 2012 En produit depuis 2014
  • 3. Objectifs Comprendre : les bases de Scala-meta Encourager : à lui donner un galop d’essai => Générer votre boilerplate <=
  • 4. Un peu de vocabulaire
  • 5. Abstract Syntax Tree (AST) Ce qui représente le programme. On (d)écrit cet AST en utilisant une arborescence de symbole
  • 6. Tout est SYMBOLE en Scala Tout ce que l’on peut définir ou donner un nom En savoir + : symbols-trees-types Symbole Mot clef ou entité Class Classe Term val, var, def, object... Lit litéral (String, Int, etc…)
  • 7. Symbole : Defn.Class Le symbole porte toutes les informations de l’entité à laquelle il fait référence Defn.Class( mods :Seq[scala.meta.Mod], // modifiers (Private, Implicit, final, sealed…) name : Type.Name, // nom du type tparams :Seq[Type.Param], // Types paramétrant la classe ctor :Ctor.Primary, // contructeur templ :Template// body de la class )
  • 8. Qu’est ce qu’une macro ? AST Code Des symboles pour décrire un AST qui génère du code
  • 9. Annotation vs def macros //def macros avec scala-reflect implicit val userWrites = Json.writes[User] //macro par annotations (scala-meta) @ShowMacro(constructorParams) case class Name(firstName: String, lastName: String)
  • 10. Utiliser des macros est facile case class User(firstName : String, lastName : String) object User { //def macro implicit val userWrites = Json.writes[User] //génère le code suivant implicit val userWrites = ( (__ "firstName").write[String] and (__ "lastName").write[String] ) (unlift(User.unapply)) }
  • 11. Mais les écrire… defn match { case q"class $className[..$classTypes] { ..$body }" => val types = classTypes.map(t => Type.Name(t.name.value)) val typesName: Seq[Name] = classTypes.map(t => Term.Name(t.name.value)) val result = q""" class $className[..$classTypes] { ..$body ..${ typesName.zipWithIndex.map { case (currentTypeName, y) => val unionXType2UnionXMethodName = Term.Name("toUnion" + y) val currentType = Type.Name(currentTypeName.value) val unionXType = Term.Name("Union" + classTypes.size) val constructorArgs : Seq[Term.Arg] = for (x <- typesName.indices) yield q"""${argByXY(x, y)}""" q"implicit def $unionXType2UnionXMethodName(t : $currentType) = $unionXType[..$types](..$constructorArgs)" } }
  • 12. Quasiquote Simplifier construction/déconstruction des symboles q"""println("hello world")""" Est équivalent à Term(Term.Name("println"), Seq(Lit.String("hello world"))) Refcard quasiquotes
  • 13. Résultat attendu @Show case class Name(firstName: String, lastName: String) object Name { def show(n : Name) : String = "Name" + "(" + List("firstName" + "=" + n.firstName), "lastName" + "=" + n.lastName).reduce(_ + "," + _) + ")" }
  • 14. Déconstruction de la class annotée @ShowMacro //class annotée case class Name(firstName: String, lastName: String) --- class ShowMacro extends scala.annotation.StaticAnnotation { inline def apply(defn: Any): Any = meta { defn match { // 1) version simple case Defn.Class(mods, name, tparams, ctor, template)=> // 2) avec companion case Seq(Defn.Class(m, n, t, c, t), companion: Defn.Object)=> //3) version simplifiée avec quasiquotes case q"case class $name(..$lFields)"=>
  • 15. Construction de l’AST q"""${cls.name.value} + "(" + //Name + ( List(..${ctor.paramss.flatMap(_.map(pp => q"""${pp.name.syntax} //List("name" + "=" +a.name, + "=" +a.${Term.Name(pp.name.value)}""" ))}) //, "age" + "=" + a.age ) .reduce(_ + "," + _) + ")" } }""" //.reduce(_ + "," + _) + ")"
  • 16. AST attendu case class Name(firstName: String, lastName: String) object Name { def show(n : Name) : String = List( "Name" + "(" + List("firstName" + "=" + n.firstName), "lastName" + "=" + n.lastName).reduce(_ + "," + _) } Gist
  • 17. Code complet package io.github.hamsters import scala.collection.immutable.Seq import scala.meta._ class ShowMacro extends scala.annotation.StaticAnnotation { inline def apply(defn: Any): Any = meta { defn match { case cls @ Defn.Class(_, _, _, ctor, _) => val show =q""" implicit def showable = new io.github.hamsters.Showable[${cls.name}] { override def format(a: ${cls.name}) ={ import io.github.hamsters.ShowableSyntax._ ${Lit.String(cls.name.value)}+ "(" + List(..${ctor.paramss.flatMap(_.map(pp => q"""${pp.name.syntax} + "=" + Show.show(a.${Term.Name(pp.name.value)})""" ))}).reduce(_ + "," + _) + ")" } }""" val companion = q"object ${Term.Name(cls.name.value)} { $show }" val res = Term.Block(Seq(cls, companion)) //abort(res.syntax) res case _ => abort(defn.pos, "Invalid annottee - you can only use @Show on case classes") } } }
  • 18. Compilation, dans un module séparé + project - macros + build.sbt lazy val macros = project.settings( libraryDependencies += "org.scalameta" %% "scalameta" % "1.8.0" % Provided) lazy val app = project.dependsOn(macros) sbt clean && sbt compile
  • 19. En savoir + Hamster : Librairie Scala compatible avec les débutants en programmation fonctionnelle (plein de macros dedans) AST Explorer : outil de visualisation Refcard quasiquotes Introduction pratique aux macros scala