SlideShare ist ein Scribd-Unternehmen logo
1 von 48
Leveraging Scala 
Macros for Better 
Validation 
Tomer Gabel, Wix 
September 2014
I Have a Dream 
• Definition: 
case class Person( 
firstName: String, 
lastName: String 
) 
implicit val personValidator = 
validator[Person] { p ⇒ 
p.firstName is notEmpty 
p.lastName is notEmpty 
}
I Have a Dream 
• Usage: 
validate(Person("Wernher", "von Braun”)) 
== Success 
validate(Person("", "No First Name”)) 
== Failure(Set(RuleViolation( 
value = "", 
constraint = "must not be empty", 
description = "firstName" 
)))
ENTER: ACCORD.
Basic Architecture 
API 
Combinator Library 
DSL 
Macro Transformation
The Accord API 
• Validation can succeed or fail 
• A failure comprises one or more violations 
sealed trait Result 
case object Success extends Result 
case class Failure(violations: Set[Violation]) 
extends Result 
• The validator typeclass: 
trait Validator[-T] extends (T ⇒ Result)
Why Macros? 
• Quick refresher: 
implicit val personValidator = 
validator[Person] { p ⇒ 
p.firstName is notEmpty 
p.lastName is notEmpty 
} 
Implicit “and” 
Automatic description 
generation
Full Disclosure 
Macros are experimental 
Macros are hard 
I will gloss over a lot of details 
… and simplify a lot of things
Abstract Syntax Trees 
• An intermediate representation of code 
– Structure (semantics) 
– Metadata (e.g. types) – optional! 
• Provided by the reflection API 
• Alas, mutable 
– Until Dotty comes along
Abstract Syntax Trees 
def method(param: String) = param.toUpperCase
Abstract Syntax Trees 
def method(param: String) = param.toUpperCase 
Apply( 
Select( 
Ident(newTermName("param")), 
newTermName("toUpperCase") 
), 
List() 
)
Abstract Syntax Trees 
def method(param: String) = param.toUpperCase 
ValDef( 
Modifiers(PARAM), 
newTermName("param"), 
Select( 
Ident(scala.Predef), 
newTypeName("String") 
), 
EmptyTree // Value 
)
Abstract Syntax Trees 
def method(param: String) = param.toUpperCase 
DefDef( 
Modifiers(), 
newTermName("method"), 
List(), // Type parameters 
List( // Parameter lists 
List(parameter) 
), 
TypeTree(), // Return type 
implementation 
)
Def Macro 101 
• Looks and acts like a normal function 
def radix(s: String, base: Int): Long 
val result = radix("2710", 16) 
// result == 10000L 
• Two fundamental differences: 
– Invoked at compile time instead of runtime 
– Operates on ASTs instead of values
Def Macro 101 
• Needs a signature & implementation 
def radix(s: String, base: Int): Long = 
macro radixImpl 
def radixImpl 
Values 
(c: Context) 
(s: c.Expr[String], base: c.Expr[Int]): 
c.Expr[Long] 
ASTs
Def Macro 101 
• What’s in a context? 
– Enclosures (position) 
– Error handling 
– Logging 
– Infrastructure
Basic Architecture 
API 
Combinator Library 
DSL 
Macro Transformation
Overview 
implicit val personValidator = 
validator[Person] { p ⇒ 
p.firstName is notEmpty 
p.lastName is notEmpty 
} 
• The validator macro: 
Macro Application 
Validation Rules 
– Rewrites each rule by addition a description 
– Aggregates rules with an and combinator
Signature 
def validator[T](v: T ⇒ Unit): Validator[T] = 
macro ValidationTransform.apply[T] 
def apply[T : c.WeakTypeTag] 
(c: Context) 
(v: c.Expr[T ⇒ Unit]): 
c.Expr[Validator[T]]
Brace 
yourselves 
Here be dragons
Walkthrough 
Search for rule 
Process rule 
Generate description 
Rewrite rule
Walkthrough 
Search for rule 
Process rule 
Generate description 
Rewrite rule
Search for Rule 
• A rule is an expression of type Validator[_] 
• We search by: 
– Recursively pattern matching over an AST 
– On match, apply a function on the subtree 
– Encoded as a partial function from Tree to R
Search for Rule 
def collectFromPattern[R] 
(tree: Tree) 
(pattern: PartialFunction[Tree, R]): List[R] = { 
var found: Vector[R] = Vector.empty 
new Traverser { 
override def traverse(subtree: Tree) { 
if (pattern isDefinedAt subtree) 
found = found :+ pattern(subtree) 
else 
super.traverse(subtree) 
} 
}.traverse(tree) 
found.toList 
}
Search for Rule 
• Putting it together: 
case class Rule(ouv: Tree, validation: Tree) 
def processRule(subtree: Tree): Rule = ??? 
def findRules(body: Tree): Seq[Rule] = { 
val validatorType = typeOf[Validator[_]] 
collectFromPattern(body) { 
case subtree if subtree.tpe <:< validatorType ⇒ 
processRule(subtree) 
} 
}
Walkthrough 
Search for rule 
Process rule 
Generate description 
Rewrite rule
Process Rule 
• The user writes: 
p.firstName is notEmpty 
• The compiler emits: 
Type: Validator[_] 
Contextualizer(p.firstName).is(notEmpty) 
Object Under Validation 
(OUV) 
Validation
Process Rule 
Contextualizer(p.firstName).is(notEmpty) 
• This is effectively an Apply AST node 
• The left-hand side is the OUV 
• The right-hand side is the validation 
– But we can use the entire expression! 
• Contextualizer is our entry point
Process Rule 
Contextualizer(p.firstName).is(notEmpty) 
Apply 
Select 
Apply 
TypeApply 
Contextualizer 
String 
Select 
Ident(“p”) 
firstName 
is 
notEmpty
Process Rule 
Contextualizer(p.firstName).is(notEmpty) 
Apply 
Select 
Apply 
TypeApply 
Contextualizer 
String 
Select 
Ident(“p”) 
firstName 
is 
notEmpty
Process Rule 
Apply 
TypeApply 
Contextualizer 
String 
Select 
Ident(“p”) 
firstName
Process Rule 
Apply 
TypeApply 
Contextualizer 
Φ 
Select 
Ident(“p”) 
firstName
Process Rule 
Apply 
TypeApply 
Contextualizer 
Φ 
Select 
Ident(“p”) 
firstName
Process Rule 
Apply 
TypeApply 
Contextualizer 
Φ 
OUV 
Φ 
Φ 
case Apply(TypeApply(Select(_, `term`), _), ouv :: Nil) ⇒
Process Rule 
• Putting it together: 
val term = newTermName("Contextualizer") 
def processRule(subtree: Tree): Rule = 
extractFromPattern(subtree) { 
case Apply(TypeApply(Select(_, `term`), _), ouv :: Nil) ⇒ 
Rule(ouv, subtree) 
} getOrElse abort(subtree.pos, "Not a valid rule")
Walkthrough 
Search for rule 
Process rule 
Generate description 
Rewrite rule
Generate Description 
Contextualizer(p.firstName).is(notEmpty) 
• Consider the object under validation 
• In this example, it is a field accessor 
• The function prototype is the entry point 
Select 
Ident(“p”) 
firstName 
validator[Person] { p ⇒ 
... 
}
Generate Description 
• How to get at the prototype? 
• The macro signature includes the rule block: 
def apply[T : c.WeakTypeTag] 
(c: Context) 
(v: c.Expr[T ⇒ Unit]): 
c.Expr[Validator[T]] 
• To extract the prototype: 
val Function(prototype :: Nil, body) = 
v.tree // prototype: ValDef
Generate Description 
• Putting it all together: 
def describeRule(rule: ValidationRule) = { 
val para = prototype.name 
val Select(Ident(`para`), description) = 
rule.ouv 
description.toString 
}
Walkthrough 
Search for rule 
Process rule 
Generate description 
Rewrite rule
Rewrite Rule 
• We’re constructing a Validator[Person] 
• A rule is itself a Validator[T]. For example: 
Contextualizer(p.firstName).is(notEmpty) 
• We need to: 
– Lift the rule to validate the enclosing type 
– Apply the description to the result
Quasiquotes 
• Provide an easy way to construct ASTs: 
Apply( 
Select( 
Ident(newTermName"x"), 
newTermName("$plus") 
), 
List( 
Ident(newTermName("y")) 
) 
) 
q"x + y"
Quasiquotes 
• Quasiquotes also let you splice trees: 
def greeting(whom: c.Expr[String]) = 
q"Hello "$whom"!" 
• And can be used in pattern matching: 
val q"$x + $y" = tree
Rewrite Rule 
Contextualizer(p.firstName).is(notEmpty) 
new Validator[Person] { 
def apply(p: Person) = { 
val validation = 
Contextualizer(p.firstName).is(notEmpty) 
validation(p.firstName) withDescription "firstName" 
} 
}
Rewrite Rule 
• Putting it all together: 
def rewriteRule(rule: ValidationRule) = { 
val desc = describeRule(rule) 
val tree = Literal(Constant(desc)) 
q""" 
new com.wix.accord.Validator[${weakTypeOf[T]}] { 
def apply($prototype) = { 
val validation = ${rule.validation} 
validation(${rule.ouv}) withDescription $tree 
} 
} 
""" 
}
The Last Mile
Epilogue 
• The finishing touch: and combinator 
def apply[T : c.WeakTypeTag] 
(c: Context) 
(v: c.Expr[T ⇒ Unit]): c.Expr[Validator[T]] = { 
val Function(prototype :: Nil, body) = v.tree 
// ... all the stuff we just discussed 
val rules = findRules(body) map rewriteRule 
val result = 
q"new com.wix.accord.combinators.And(..$rules)" 
c.Expr[Validator[T]](result) 
}
tomer@tomergabel.com 
@tomerg 
http://il.linkedin.com/in/tomergabel 
Check out Accord at: 
http://github.com/wix/accord 
Thank you for listening 
WE’RE DONE 
HERE!

Weitere ähnliche Inhalte

Was ist angesagt?

The Ring programming language version 1.8 book - Part 41 of 202
The Ring programming language version 1.8 book - Part 41 of 202The Ring programming language version 1.8 book - Part 41 of 202
The Ring programming language version 1.8 book - Part 41 of 202Mahmoud Samir Fayed
 
Postgres rules
Postgres rulesPostgres rules
Postgres rulesgisborne
 
The Ring programming language version 1.5.1 book - Part 34 of 180
The Ring programming language version 1.5.1 book - Part 34 of 180The Ring programming language version 1.5.1 book - Part 34 of 180
The Ring programming language version 1.5.1 book - Part 34 of 180Mahmoud Samir Fayed
 
The Ring programming language version 1.5.1 book - Part 33 of 180
The Ring programming language version 1.5.1 book - Part 33 of 180The Ring programming language version 1.5.1 book - Part 33 of 180
The Ring programming language version 1.5.1 book - Part 33 of 180Mahmoud Samir Fayed
 
Grails GORM - You Know SQL. You Know Queries. Here's GORM.
Grails GORM - You Know SQL. You Know Queries. Here's GORM.Grails GORM - You Know SQL. You Know Queries. Here's GORM.
Grails GORM - You Know SQL. You Know Queries. Here's GORM.Ted Vinke
 
Clojure vs Design Patterns
Clojure vs Design PatternsClojure vs Design Patterns
Clojure vs Design PatternsRon Toland
 
Json and SQL DB serialization Introduction with Play! and Slick
Json and SQL DB serialization Introduction with Play! and SlickJson and SQL DB serialization Introduction with Play! and Slick
Json and SQL DB serialization Introduction with Play! and SlickStephen Kemmerling
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testingVincent Pradeilles
 
MCE^3 - Hannes Verlinde - Let The Symbols Do The Work
MCE^3 - Hannes Verlinde - Let The Symbols Do The WorkMCE^3 - Hannes Verlinde - Let The Symbols Do The Work
MCE^3 - Hannes Verlinde - Let The Symbols Do The WorkPROIDEA
 

Was ist angesagt? (17)

Gorm
GormGorm
Gorm
 
The Ring programming language version 1.8 book - Part 41 of 202
The Ring programming language version 1.8 book - Part 41 of 202The Ring programming language version 1.8 book - Part 41 of 202
The Ring programming language version 1.8 book - Part 41 of 202
 
Postgres rules
Postgres rulesPostgres rules
Postgres rules
 
Java Cheat Sheet
Java Cheat SheetJava Cheat Sheet
Java Cheat Sheet
 
The Ring programming language version 1.5.1 book - Part 34 of 180
The Ring programming language version 1.5.1 book - Part 34 of 180The Ring programming language version 1.5.1 book - Part 34 of 180
The Ring programming language version 1.5.1 book - Part 34 of 180
 
Python : Dictionaries
Python : DictionariesPython : Dictionaries
Python : Dictionaries
 
Groovy unleashed
Groovy unleashed Groovy unleashed
Groovy unleashed
 
The Ring programming language version 1.5.1 book - Part 33 of 180
The Ring programming language version 1.5.1 book - Part 33 of 180The Ring programming language version 1.5.1 book - Part 33 of 180
The Ring programming language version 1.5.1 book - Part 33 of 180
 
Grails GORM - You Know SQL. You Know Queries. Here's GORM.
Grails GORM - You Know SQL. You Know Queries. Here's GORM.Grails GORM - You Know SQL. You Know Queries. Here's GORM.
Grails GORM - You Know SQL. You Know Queries. Here's GORM.
 
Clojure vs Design Patterns
Clojure vs Design PatternsClojure vs Design Patterns
Clojure vs Design Patterns
 
Json and SQL DB serialization Introduction with Play! and Slick
Json and SQL DB serialization Introduction with Play! and SlickJson and SQL DB serialization Introduction with Play! and Slick
Json and SQL DB serialization Introduction with Play! and Slick
 
What is new in Java 8
What is new in Java 8What is new in Java 8
What is new in Java 8
 
JS OO and Closures
JS OO and ClosuresJS OO and Closures
JS OO and Closures
 
Scala 2013 review
Scala 2013 reviewScala 2013 review
Scala 2013 review
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testing
 
MCE^3 - Hannes Verlinde - Let The Symbols Do The Work
MCE^3 - Hannes Verlinde - Let The Symbols Do The WorkMCE^3 - Hannes Verlinde - Let The Symbols Do The Work
MCE^3 - Hannes Verlinde - Let The Symbols Do The Work
 
Python programming : Standard Input and Output
Python programming : Standard Input and OutputPython programming : Standard Input and Output
Python programming : Standard Input and Output
 

Ähnlich wie Leveraging Scala Macros for Better Validation

PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsBastian Feder
 
Ti1220 Lecture 7: Polymorphism
Ti1220 Lecture 7: PolymorphismTi1220 Lecture 7: Polymorphism
Ti1220 Lecture 7: PolymorphismEelco Visser
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2Yi-Huan Chan
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentationVan Huong
 
API first with Swagger and Scala by Slava Schmidt
API first with Swagger and Scala by  Slava SchmidtAPI first with Swagger and Scala by  Slava Schmidt
API first with Swagger and Scala by Slava SchmidtJavaDayUA
 
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...ICS User Group
 
An excuse to Try, Either, folding, and Future. sequence
An excuse to Try, Either, folding, and Future. sequenceAn excuse to Try, Either, folding, and Future. sequence
An excuse to Try, Either, folding, and Future. sequenceGermán Ferrari
 
Session 08 - Arrays and Methods
Session 08 - Arrays and MethodsSession 08 - Arrays and Methods
Session 08 - Arrays and MethodsSiddharthSelenium
 

Ähnlich wie Leveraging Scala Macros for Better Validation (20)

Java gets a closure
Java gets a closureJava gets a closure
Java gets a closure
 
Scala
ScalaScala
Scala
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
 
Ti1220 Lecture 7: Polymorphism
Ti1220 Lecture 7: PolymorphismTi1220 Lecture 7: Polymorphism
Ti1220 Lecture 7: Polymorphism
 
Scala in Places API
Scala in Places APIScala in Places API
Scala in Places API
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Php & my sql
Php & my sqlPhp & my sql
Php & my sql
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentation
 
API first with Swagger and Scala by Slava Schmidt
API first with Swagger and Scala by  Slava SchmidtAPI first with Swagger and Scala by  Slava Schmidt
API first with Swagger and Scala by Slava Schmidt
 
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
An excuse to Try, Either, folding, and Future. sequence
An excuse to Try, Either, folding, and Future. sequenceAn excuse to Try, Either, folding, and Future. sequence
An excuse to Try, Either, folding, and Future. sequence
 
Session 08 - Arrays and Methods
Session 08 - Arrays and MethodsSession 08 - Arrays and Methods
Session 08 - Arrays and Methods
 
Java SE 8
Java SE 8Java SE 8
Java SE 8
 
ScalaBlitz
ScalaBlitzScalaBlitz
ScalaBlitz
 

Mehr von Tomer Gabel

How shit works: Time
How shit works: TimeHow shit works: Time
How shit works: TimeTomer Gabel
 
Nondeterministic Software for the Rest of Us
Nondeterministic Software for the Rest of UsNondeterministic Software for the Rest of Us
Nondeterministic Software for the Rest of UsTomer Gabel
 
Slaying Sacred Cows: Deconstructing Dependency Injection
Slaying Sacred Cows: Deconstructing Dependency InjectionSlaying Sacred Cows: Deconstructing Dependency Injection
Slaying Sacred Cows: Deconstructing Dependency InjectionTomer Gabel
 
An Abridged Guide to Event Sourcing
An Abridged Guide to Event SourcingAn Abridged Guide to Event Sourcing
An Abridged Guide to Event SourcingTomer Gabel
 
How shit works: the CPU
How shit works: the CPUHow shit works: the CPU
How shit works: the CPUTomer Gabel
 
How Shit Works: Storage
How Shit Works: StorageHow Shit Works: Storage
How Shit Works: StorageTomer Gabel
 
Java 8 and Beyond, a Scala Story
Java 8 and Beyond, a Scala StoryJava 8 and Beyond, a Scala Story
Java 8 and Beyond, a Scala StoryTomer Gabel
 
The Wix Microservice Stack
The Wix Microservice StackThe Wix Microservice Stack
The Wix Microservice StackTomer Gabel
 
Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)Tomer Gabel
 
Scala Refactoring for Fun and Profit
Scala Refactoring for Fun and ProfitScala Refactoring for Fun and Profit
Scala Refactoring for Fun and ProfitTomer Gabel
 
Onboarding at Scale
Onboarding at ScaleOnboarding at Scale
Onboarding at ScaleTomer Gabel
 
Scala in the Wild
Scala in the WildScala in the Wild
Scala in the WildTomer Gabel
 
Speaking Scala: Refactoring for Fun and Profit (Workshop)
Speaking Scala: Refactoring for Fun and Profit (Workshop)Speaking Scala: Refactoring for Fun and Profit (Workshop)
Speaking Scala: Refactoring for Fun and Profit (Workshop)Tomer Gabel
 
Put Your Thinking CAP On
Put Your Thinking CAP OnPut Your Thinking CAP On
Put Your Thinking CAP OnTomer Gabel
 
A Field Guide to DSL Design in Scala
A Field Guide to DSL Design in ScalaA Field Guide to DSL Design in Scala
A Field Guide to DSL Design in ScalaTomer Gabel
 
Functional Leap of Faith (Keynote at JDay Lviv 2014)
Functional Leap of Faith (Keynote at JDay Lviv 2014)Functional Leap of Faith (Keynote at JDay Lviv 2014)
Functional Leap of Faith (Keynote at JDay Lviv 2014)Tomer Gabel
 
Scala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesTomer Gabel
 
5 Bullets to Scala Adoption
5 Bullets to Scala Adoption5 Bullets to Scala Adoption
5 Bullets to Scala AdoptionTomer Gabel
 
Nashorn: JavaScript that doesn’t suck (ILJUG)
Nashorn: JavaScript that doesn’t suck (ILJUG)Nashorn: JavaScript that doesn’t suck (ILJUG)
Nashorn: JavaScript that doesn’t suck (ILJUG)Tomer Gabel
 
Ponies and Unicorns With Scala
Ponies and Unicorns With ScalaPonies and Unicorns With Scala
Ponies and Unicorns With ScalaTomer Gabel
 

Mehr von Tomer Gabel (20)

How shit works: Time
How shit works: TimeHow shit works: Time
How shit works: Time
 
Nondeterministic Software for the Rest of Us
Nondeterministic Software for the Rest of UsNondeterministic Software for the Rest of Us
Nondeterministic Software for the Rest of Us
 
Slaying Sacred Cows: Deconstructing Dependency Injection
Slaying Sacred Cows: Deconstructing Dependency InjectionSlaying Sacred Cows: Deconstructing Dependency Injection
Slaying Sacred Cows: Deconstructing Dependency Injection
 
An Abridged Guide to Event Sourcing
An Abridged Guide to Event SourcingAn Abridged Guide to Event Sourcing
An Abridged Guide to Event Sourcing
 
How shit works: the CPU
How shit works: the CPUHow shit works: the CPU
How shit works: the CPU
 
How Shit Works: Storage
How Shit Works: StorageHow Shit Works: Storage
How Shit Works: Storage
 
Java 8 and Beyond, a Scala Story
Java 8 and Beyond, a Scala StoryJava 8 and Beyond, a Scala Story
Java 8 and Beyond, a Scala Story
 
The Wix Microservice Stack
The Wix Microservice StackThe Wix Microservice Stack
The Wix Microservice Stack
 
Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)
 
Scala Refactoring for Fun and Profit
Scala Refactoring for Fun and ProfitScala Refactoring for Fun and Profit
Scala Refactoring for Fun and Profit
 
Onboarding at Scale
Onboarding at ScaleOnboarding at Scale
Onboarding at Scale
 
Scala in the Wild
Scala in the WildScala in the Wild
Scala in the Wild
 
Speaking Scala: Refactoring for Fun and Profit (Workshop)
Speaking Scala: Refactoring for Fun and Profit (Workshop)Speaking Scala: Refactoring for Fun and Profit (Workshop)
Speaking Scala: Refactoring for Fun and Profit (Workshop)
 
Put Your Thinking CAP On
Put Your Thinking CAP OnPut Your Thinking CAP On
Put Your Thinking CAP On
 
A Field Guide to DSL Design in Scala
A Field Guide to DSL Design in ScalaA Field Guide to DSL Design in Scala
A Field Guide to DSL Design in Scala
 
Functional Leap of Faith (Keynote at JDay Lviv 2014)
Functional Leap of Faith (Keynote at JDay Lviv 2014)Functional Leap of Faith (Keynote at JDay Lviv 2014)
Functional Leap of Faith (Keynote at JDay Lviv 2014)
 
Scala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type Classes
 
5 Bullets to Scala Adoption
5 Bullets to Scala Adoption5 Bullets to Scala Adoption
5 Bullets to Scala Adoption
 
Nashorn: JavaScript that doesn’t suck (ILJUG)
Nashorn: JavaScript that doesn’t suck (ILJUG)Nashorn: JavaScript that doesn’t suck (ILJUG)
Nashorn: JavaScript that doesn’t suck (ILJUG)
 
Ponies and Unicorns With Scala
Ponies and Unicorns With ScalaPonies and Unicorns With Scala
Ponies and Unicorns With Scala
 

Kürzlich hochgeladen

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfVishalKumarJha10
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfproinshot.com
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...kalichargn70th171
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 

Kürzlich hochgeladen (20)

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 

Leveraging Scala Macros for Better Validation

  • 1. Leveraging Scala Macros for Better Validation Tomer Gabel, Wix September 2014
  • 2. I Have a Dream • Definition: case class Person( firstName: String, lastName: String ) implicit val personValidator = validator[Person] { p ⇒ p.firstName is notEmpty p.lastName is notEmpty }
  • 3. I Have a Dream • Usage: validate(Person("Wernher", "von Braun”)) == Success validate(Person("", "No First Name”)) == Failure(Set(RuleViolation( value = "", constraint = "must not be empty", description = "firstName" )))
  • 5. Basic Architecture API Combinator Library DSL Macro Transformation
  • 6. The Accord API • Validation can succeed or fail • A failure comprises one or more violations sealed trait Result case object Success extends Result case class Failure(violations: Set[Violation]) extends Result • The validator typeclass: trait Validator[-T] extends (T ⇒ Result)
  • 7. Why Macros? • Quick refresher: implicit val personValidator = validator[Person] { p ⇒ p.firstName is notEmpty p.lastName is notEmpty } Implicit “and” Automatic description generation
  • 8. Full Disclosure Macros are experimental Macros are hard I will gloss over a lot of details … and simplify a lot of things
  • 9. Abstract Syntax Trees • An intermediate representation of code – Structure (semantics) – Metadata (e.g. types) – optional! • Provided by the reflection API • Alas, mutable – Until Dotty comes along
  • 10. Abstract Syntax Trees def method(param: String) = param.toUpperCase
  • 11. Abstract Syntax Trees def method(param: String) = param.toUpperCase Apply( Select( Ident(newTermName("param")), newTermName("toUpperCase") ), List() )
  • 12. Abstract Syntax Trees def method(param: String) = param.toUpperCase ValDef( Modifiers(PARAM), newTermName("param"), Select( Ident(scala.Predef), newTypeName("String") ), EmptyTree // Value )
  • 13. Abstract Syntax Trees def method(param: String) = param.toUpperCase DefDef( Modifiers(), newTermName("method"), List(), // Type parameters List( // Parameter lists List(parameter) ), TypeTree(), // Return type implementation )
  • 14. Def Macro 101 • Looks and acts like a normal function def radix(s: String, base: Int): Long val result = radix("2710", 16) // result == 10000L • Two fundamental differences: – Invoked at compile time instead of runtime – Operates on ASTs instead of values
  • 15. Def Macro 101 • Needs a signature & implementation def radix(s: String, base: Int): Long = macro radixImpl def radixImpl Values (c: Context) (s: c.Expr[String], base: c.Expr[Int]): c.Expr[Long] ASTs
  • 16. Def Macro 101 • What’s in a context? – Enclosures (position) – Error handling – Logging – Infrastructure
  • 17. Basic Architecture API Combinator Library DSL Macro Transformation
  • 18. Overview implicit val personValidator = validator[Person] { p ⇒ p.firstName is notEmpty p.lastName is notEmpty } • The validator macro: Macro Application Validation Rules – Rewrites each rule by addition a description – Aggregates rules with an and combinator
  • 19. Signature def validator[T](v: T ⇒ Unit): Validator[T] = macro ValidationTransform.apply[T] def apply[T : c.WeakTypeTag] (c: Context) (v: c.Expr[T ⇒ Unit]): c.Expr[Validator[T]]
  • 20. Brace yourselves Here be dragons
  • 21. Walkthrough Search for rule Process rule Generate description Rewrite rule
  • 22. Walkthrough Search for rule Process rule Generate description Rewrite rule
  • 23. Search for Rule • A rule is an expression of type Validator[_] • We search by: – Recursively pattern matching over an AST – On match, apply a function on the subtree – Encoded as a partial function from Tree to R
  • 24. Search for Rule def collectFromPattern[R] (tree: Tree) (pattern: PartialFunction[Tree, R]): List[R] = { var found: Vector[R] = Vector.empty new Traverser { override def traverse(subtree: Tree) { if (pattern isDefinedAt subtree) found = found :+ pattern(subtree) else super.traverse(subtree) } }.traverse(tree) found.toList }
  • 25. Search for Rule • Putting it together: case class Rule(ouv: Tree, validation: Tree) def processRule(subtree: Tree): Rule = ??? def findRules(body: Tree): Seq[Rule] = { val validatorType = typeOf[Validator[_]] collectFromPattern(body) { case subtree if subtree.tpe <:< validatorType ⇒ processRule(subtree) } }
  • 26. Walkthrough Search for rule Process rule Generate description Rewrite rule
  • 27. Process Rule • The user writes: p.firstName is notEmpty • The compiler emits: Type: Validator[_] Contextualizer(p.firstName).is(notEmpty) Object Under Validation (OUV) Validation
  • 28. Process Rule Contextualizer(p.firstName).is(notEmpty) • This is effectively an Apply AST node • The left-hand side is the OUV • The right-hand side is the validation – But we can use the entire expression! • Contextualizer is our entry point
  • 29. Process Rule Contextualizer(p.firstName).is(notEmpty) Apply Select Apply TypeApply Contextualizer String Select Ident(“p”) firstName is notEmpty
  • 30. Process Rule Contextualizer(p.firstName).is(notEmpty) Apply Select Apply TypeApply Contextualizer String Select Ident(“p”) firstName is notEmpty
  • 31. Process Rule Apply TypeApply Contextualizer String Select Ident(“p”) firstName
  • 32. Process Rule Apply TypeApply Contextualizer Φ Select Ident(“p”) firstName
  • 33. Process Rule Apply TypeApply Contextualizer Φ Select Ident(“p”) firstName
  • 34. Process Rule Apply TypeApply Contextualizer Φ OUV Φ Φ case Apply(TypeApply(Select(_, `term`), _), ouv :: Nil) ⇒
  • 35. Process Rule • Putting it together: val term = newTermName("Contextualizer") def processRule(subtree: Tree): Rule = extractFromPattern(subtree) { case Apply(TypeApply(Select(_, `term`), _), ouv :: Nil) ⇒ Rule(ouv, subtree) } getOrElse abort(subtree.pos, "Not a valid rule")
  • 36. Walkthrough Search for rule Process rule Generate description Rewrite rule
  • 37. Generate Description Contextualizer(p.firstName).is(notEmpty) • Consider the object under validation • In this example, it is a field accessor • The function prototype is the entry point Select Ident(“p”) firstName validator[Person] { p ⇒ ... }
  • 38. Generate Description • How to get at the prototype? • The macro signature includes the rule block: def apply[T : c.WeakTypeTag] (c: Context) (v: c.Expr[T ⇒ Unit]): c.Expr[Validator[T]] • To extract the prototype: val Function(prototype :: Nil, body) = v.tree // prototype: ValDef
  • 39. Generate Description • Putting it all together: def describeRule(rule: ValidationRule) = { val para = prototype.name val Select(Ident(`para`), description) = rule.ouv description.toString }
  • 40. Walkthrough Search for rule Process rule Generate description Rewrite rule
  • 41. Rewrite Rule • We’re constructing a Validator[Person] • A rule is itself a Validator[T]. For example: Contextualizer(p.firstName).is(notEmpty) • We need to: – Lift the rule to validate the enclosing type – Apply the description to the result
  • 42. Quasiquotes • Provide an easy way to construct ASTs: Apply( Select( Ident(newTermName"x"), newTermName("$plus") ), List( Ident(newTermName("y")) ) ) q"x + y"
  • 43. Quasiquotes • Quasiquotes also let you splice trees: def greeting(whom: c.Expr[String]) = q"Hello "$whom"!" • And can be used in pattern matching: val q"$x + $y" = tree
  • 44. Rewrite Rule Contextualizer(p.firstName).is(notEmpty) new Validator[Person] { def apply(p: Person) = { val validation = Contextualizer(p.firstName).is(notEmpty) validation(p.firstName) withDescription "firstName" } }
  • 45. Rewrite Rule • Putting it all together: def rewriteRule(rule: ValidationRule) = { val desc = describeRule(rule) val tree = Literal(Constant(desc)) q""" new com.wix.accord.Validator[${weakTypeOf[T]}] { def apply($prototype) = { val validation = ${rule.validation} validation(${rule.ouv}) withDescription $tree } } """ }
  • 47. Epilogue • The finishing touch: and combinator def apply[T : c.WeakTypeTag] (c: Context) (v: c.Expr[T ⇒ Unit]): c.Expr[Validator[T]] = { val Function(prototype :: Nil, body) = v.tree // ... all the stuff we just discussed val rules = findRules(body) map rewriteRule val result = q"new com.wix.accord.combinators.And(..$rules)" c.Expr[Validator[T]](result) }
  • 48. tomer@tomergabel.com @tomerg http://il.linkedin.com/in/tomergabel Check out Accord at: http://github.com/wix/accord Thank you for listening WE’RE DONE HERE!

Hinweis der Redaktion

  1. Image source: http://en.wikipedia.org/wiki/File:Martin_Luther_King_-_March_on_Washington.jpg
  2. Image source: https://www.flickr.com/photos/leo-gruebler/6347903993
  3. Image source: https://www.flickr.com/photos/wwarby/11271811524/in/photostream/
  4. Number image source: http://pixabay.com/en/count-numbers-digits-display-147393/
  5. Number image source: http://pixabay.com/en/count-numbers-digits-display-147393/
  6. Number image source: http://pixabay.com/en/count-numbers-digits-display-147393/
  7. Number image source: http://pixabay.com/en/count-numbers-digits-display-147393/
  8. Number image source: http://pixabay.com/en/count-numbers-digits-display-147393/
  9. Image source: https://www.flickr.com/photos/bevgoodwin/8608320577