Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Groovy Domain Specific Languages

Groovy Domain Specific Languages

Overview of the many techniques that can be used to developer Domain-Specific Languages with Groovy

Guillaume Laforge

April 26, 2012
Tweet

More Decks by Guillaume Laforge

Other Decks in Technology

Transcript

  1. Guillaume Laforge • Groovy Project Manager at VMware • Initiator

    of the Grails framework • Creator of the Gaelyk and Caelyf toolkits • Co-author of Groovy in Action • Follow me on... • My blog: http://glaforge.appspot.com • Twitter: @glaforge • Google+: http://gplus.to/glaforge 3
  2. Domain-Specific Languages • Wikipedia definition A Domain-Specific Language is a

    programming language or executable specification language that offers, through appropriate notations and abstractions, expressive power focused on, and usually restricted to, a particular problem domain. • In contrast to General Purprose Languages • Also known as: fluent / human interfaces, language oriented programming, little or mini languages, macros, business natural languages... 5 { }
  3. Technical examples <?xml version="1.0"?> <xsl:stylesheetversion="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml"/> <xsl:template match="*">

    <xsl:element name="{name()}"> <xsl:for-each select="@*"> <xsl:element name="{name()}"> <xsl:value-of select="."/> </xsl:element> </xsl:for-each> <xsl:apply-templates select="*|text()"/> </xsl:element> </xsl:template> </xsl:stylesheet> <?xml version="1.0"?> <GTK-Interface> <widget> <class>GtkWindow</class> <name>HelloWindow</name> <border_width>5</border_width> <Signal> <name>destroy</name> <handler>gtk_main_quit</handler> </Signal> <title>Hello</title> <type>GTK_WINDOW_TOPLEVEL</type> <position>GTK_WIN_POS_NONE</position> <allow_shrink>True</allow_shrink> <allow_grow>True</allow_grow> <auto_shrink>False</auto_shrink> <widget> <class>GtkButton</class> <name>Hello World</name> <can_focus>True</can_focus> <label>Hello World</label> </widget> </widget> </GTK-Interface> # Poll this site first each cycle. poll pop.provider.net proto pop3 user "jsmith" with pass "secret1" is "smith" here user jones with pass "secret2" is "jjones" here with options keep # Poll this site second, unless Lord Voldemort zaps us first. poll billywig.hogwarts.com with proto imap: user harry_potter with pass "floo" is harry_potter here # Poll this site third in the cycle. # Password will be fetched from ~/.netrc poll mailhost.net with proto imap: user esr is esr here Glade XSLT fetchmail Regex "x.z?z{1,3}y" SQL SELECT * FROM TABLE WHERE NAME LIKE '%SMI' ORDER BY NAME
  4. Antimalaria drug resistance simulation HR skills representation Insurance policy risk

    calculation engine Market data feeds analysis Loan acceptance rules engine Nuclear safety simulations
  5. Goals of DSLs • Use a more expressive language than

    a general-purpose one • Share a common metaphor of understanding between developers and subject matter experts • Have domain experts help with the design of the business logic of an application • Avoid cluttering business code with too much boilerplate technical code thanks to a clean separation • Let business rules have their own lifecycle 8
  6. Pros and cons Pros • Domain experts can help, validate,

    modify, and often develop DSL programs • Somewhat self-documenting • Enhance quality, productivity, reliability, maintainability, portability, reusability • Safety; as long as the language constructs are safe, any DSL sentence can be considered safe Cons • Learning cost vs. limited applicability • Cost of designing, implementing & maintaining DSLs as well as tools/IDEs • Attaining proper scope • Trade-offs between domain specificity and general purpose language constructs • Efficiency cost • Proliferation of similar non-standard DSLs 9
  7. Groovy provides... • A flexible and malleable syntax • scripts,

    native syntax constructs (list, map, ranges), closures, less punctuation... • Compile-time and runtime meta-programming • metaclasses, AST transformations • also operator overloading • The ability to easily integrate into Java / Spring apps • also security and safety 10
  8. Now how can we control it? 18 import)static)mars.Direction.*; import)mars.Robot; public)class)Command!{

    ))))public)static)void)main(String[]!args)!{ !!!!!!!!Robot!robot!=)new!Robot(); !!!!!!!!robot.move(left); !!!!} }
  9. Now how can we control it? 18 import)static)mars.Direction.*; import)mars.Robot; public)class)Command!{

    ))))public)static)void)main(String[]!args)!{ !!!!!!!!Robot!robot!=)new!Robot(); !!!!!!!!robot.move(left); !!!!} } Syntactical noise!
  10. Now how can we control it? 18 import)static)mars.Direction.*; import)mars.Robot; public)class)Command!{

    ))))public)static)void)main(String[]!args)!{ !!!!!!!!Robot!robot!=)new!Robot(); !!!!!!!!robot.move(left); !!!!} } Syntactical noise! ))))))))))))))))))))))))))))))— )))))))))))))))))— —————————————————————— ))))———————————————————————————————————————— ))))))))—————))))))))))))))))))))— ))))))))))))))))))—))))—— ))))— —
  11. Scripts vs Classes Optional semicolons & parens 19 import)static)mars.Direction.* import)mars.Robot

    !!!!!!!!def))!robot!=)new!Robot() !!!!!!!!robot.move!left Optional typing
  12. Scripts vs Classes Optional semicolons & parens 19 import)static)mars.Direction.* import)mars.Robot

    !!!!!!!!def))!robot!=)new!Robot() !!!!!!!!robot.move!left But I don’t want to compile a script for every command! Optional typing
  13. Integration mechanisms • Different solutions available: • Groovy’s own mechanisms

    • GroovyScriptEngine, Eval, GroovyClassLoader, GroovyShell • Java 6: javax.script.* / JSR-223 • Groovy provides a JSR-223 implementation • Spring’s lang namespace • Groovy provides the highest level of flexibility and customization, but JSR-223 is a standard... 22
  14. Integration mechanisms • Different solutions available: • Groovy’s own mechanisms

    • GroovyScriptEngine, Eval, GroovyClassLoader, GroovyShell • Java 6: javax.script.* / JSR-223 • Groovy provides a JSR-223 implementation • Spring’s lang namespace • Groovy provides the highest level of flexibility and customization, but JSR-223 is a standard... 22
  15. What’s wrong with our DSL? 23 import)static)mars.Direction.* import)mars.Robot def)robot!=)new!Robot() robot.move!left

    Can’t we hide those imports? Can’t we inject the robot? Do we really need to repeat ‘robot’?
  16. Let’s inject a robot! • We can pass data in

    / out of scripts through the Binding • it’s basically just like a map of variable name keys and their associated values 26
  17. Let’s inject a robot! • We can pass data in

    / out of scripts through the Binding • it’s basically just like a map of variable name keys and their associated values 26 def)binding!=)new!Binding([ !!!!robot:!new!Robot() ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") )
  18. Let’s inject a robot! • We can pass data in

    / out of scripts through the Binding • it’s basically just like a map of variable name keys and their associated values 26 def)binding!=)new!Binding([ !!!!robot:!new!Robot() ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") ) integration.groovy
  19. How to inject the direction? • Using the binding... 28

    def)binding!=)new!Binding([ !!!!robot:!new!Robot(), !!!!left:!!!!!Direction.left, !!!!right:!!!!Direction.right, !!!!backward:!Direction.backward, !!!!forward:!!Direction.forward ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") )
  20. How to inject the direction? • Using the binding... 28

    def)binding!=)new!Binding([ !!!!robot:!new!Robot(), !!!!left:!!!!!Direction.left, !!!!right:!!!!Direction.right, !!!!backward:!Direction.backward, !!!!forward:!!Direction.forward ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") ) Fragile in case of new directions!
  21. How to inject the direction? • Using the binding... 29

    def)binding!=)new!Binding([ !!!!robot:!new!Robot(), !!!!*:!Direction.values() !!!!!!!!!!!!.collectEntries!{ !!!!!!!!!!!!!!!![(it.name()):!it] !!!!!!!!!!!!} ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") )
  22. Compilation customizers • Ability to apply some customization to the

    Groovy compilation process • Three available customizers • ImportCustomizer: add transparent imports • ASTTransformationCustomizer: injects an AST transform • SecureASTCustomizer: restrict the groovy language to an allowed subset • But you can implement your own 31
  23. AST transformation customizer 34 def!configuration!=!new!CompilerConfiguration() ! def!imports!=!new!ImportCustomizer() imports.addStaticStar(mars.Direction.name) configuration.addCompilationCustomizers(imports, !!!!!!!!!!!!!new!ASTTransformationCustomizer(Log))

    ! new!GroovyShell(new!Binding([robot:!new)Robot()]),!!!!!!! ! ! !!!!!!!!!!!!!!!!configuration) !!!!.evaluate("robot.move!left"!+!"\n" !!!!!!!!!!!!!!"log.info!‘Robot!moved’")!!!!!!!!!!!
  24. AST transformation customizer 34 def!configuration!=!new!CompilerConfiguration() ! def!imports!=!new!ImportCustomizer() imports.addStaticStar(mars.Direction.name) configuration.addCompilationCustomizers(imports, !!!!!!!!!!!!!new!ASTTransformationCustomizer(Log))

    ! new!GroovyShell(new!Binding([robot:!new)Robot()]),!!!!!!! ! ! !!!!!!!!!!!!!!!!configuration) !!!!.evaluate("robot.move!left"!+!"\n" !!!!!!!!!!!!!!"log.info!‘Robot!moved’")!!!!!!!!!!! @Log injects a logger in scripts and classes
  25. Secure AST customizer • Let’s setup our environment • an

    import customizer to import java.lang.Math.* • prepare a secure AST customizer 36 def%imports%=%new%ImportCustomizer().addStaticStars('java.lang.Math') def%secure%=%new%SecureASTCustomizer() Idea: Secure the rocket’s onboard trajectory calculation system by allowing only math expressions to be evaluated by the calculator
  26. Secure AST customizer 37 ... secure.with!{ //!disallow!closure!creation closuresAllowed!=!false! //!disallow!method!definitions methodDefinitionAllowed!=!false!

    ! //!empty!white!list!=>!forbid!imports importsWhitelist!=![]! staticImportsWhitelist!=![] //!only!allow!the!java.lang.Math.*!static!import staticStarImportsWhitelist!=!['java.lang.Math'] ...
  27. Secure AST customizer 37 ... secure.with!{ //!disallow!closure!creation closuresAllowed!=!false! //!disallow!method!definitions methodDefinitionAllowed!=!false!

    ! //!empty!white!list!=>!forbid!imports importsWhitelist!=![]! staticImportsWhitelist!=![] //!only!allow!the!java.lang.Math.*!static!import staticStarImportsWhitelist!=!['java.lang.Math'] ... Disallow closures and methods
  28. Secure AST customizer 37 ... secure.with!{ //!disallow!closure!creation closuresAllowed!=!false! //!disallow!method!definitions methodDefinitionAllowed!=!false!

    ! //!empty!white!list!=>!forbid!imports importsWhitelist!=![]! staticImportsWhitelist!=![] //!only!allow!the!java.lang.Math.*!static!import staticStarImportsWhitelist!=!['java.lang.Math'] ... Disallow closures and methods Black / white list imports
  29. Secure AST customizer 38 ... //%language%tokens%allowed tokensWhitelist%=%[ PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,% COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,% COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL

    ] % //%types%allowed%to%be%used%(including%primitive%types) constantTypesClassesWhiteList%=%[ Integer,%Float,%Long,%Double,%BigDecimal,% Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE ] % //%classes%who%are%allowed%to%be%receivers%of%method%calls receiversClassesWhiteList%=%[% Math,%Integer,%Float,%Double,%Long,%BigDecimal%] } ...
  30. Secure AST customizer 38 ... //%language%tokens%allowed tokensWhitelist%=%[ PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,% COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,% COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL

    ] % //%types%allowed%to%be%used%(including%primitive%types) constantTypesClassesWhiteList%=%[ Integer,%Float,%Long,%Double,%BigDecimal,% Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE ] % //%classes%who%are%allowed%to%be%receivers%of%method%calls receiversClassesWhiteList%=%[% Math,%Integer,%Float,%Double,%Long,%BigDecimal%] } ... You can build a subset of the Groovy syntax!
  31. Secure AST customizer 38 ... //%language%tokens%allowed tokensWhitelist%=%[ PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,% COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,% COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL

    ] % //%types%allowed%to%be%used%(including%primitive%types) constantTypesClassesWhiteList%=%[ Integer,%Float,%Long,%Double,%BigDecimal,% Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE ] % //%classes%who%are%allowed%to%be%receivers%of%method%calls receiversClassesWhiteList%=%[% Math,%Integer,%Float,%Double,%Long,%BigDecimal%] } ... You can build a subset of the Groovy syntax! Black / white list usage of classes
  32. Secure AST customizer • Ready to evaluate our flight equations!

    • But the following would have failed: 39 shell.evaluate%'System.exit(0)' def%config%=%new%CompilerConfiguration() config.addCompilationCustomizers(imports,%secure) def%shell%=%new%GroovyShell(config) % shell.evaluate%'cos%PI/3'
  33. How to remove the ‘robot’? • Instead of calling the

    move() method on the robot instance, we should be able to call the move() method directly from within the script • Two approaches: 42 • Inject a ‘move’ closure in the binding with a method pointer • Use a base script class with a ‘move’ method delegating to the robot
  34. Inject a closure in the binding 43 def$robot%=%new%Robot() binding%=$new%Binding([ %%%%robot:%robot,

    %%%%*:%Direction.values() %%%%%%%%%%%%.collectEntries%{ %%%%%%%%%%%%%%%%[(it.name()):%it] %%%%%%%%%%%%}, %%%%move:%robot.&move ])
  35. Inject a closure in the binding 43 def$robot%=%new%Robot() binding%=$new%Binding([ %%%%robot:%robot,

    %%%%*:%Direction.values() %%%%%%%%%%%%.collectEntries%{ %%%%%%%%%%%%%%%%[(it.name()):%it] %%%%%%%%%%%%}, %%%%move:%robot.&move ]) Method pointer (a closure) on robot’s move instance method
  36. Define a base script class 44 abstract)class!RobotBaseScriptClass!!! !!!!!!!extends!Script!{ !!!!void!move(Direction!dir)!{ !!!!!!!!def)robot!=!this.binding.robot

    !!!!!!!!robot.move!dir !!!!} } The move() method is now at the script level Access the robot through the script’s binding
  37. What we could do now is... 49 move!left,!at:!3.km/h How to

    add a km property to numbers? Mix of named and normal parameters
  38. Adding properties to numbers • We need to: • define

    units, distance and speed • have a nice notation for them • that’s where we add properties to numbers! 50
  39. Unit enum and Distance class 51 enum$DistanceUnit%{ %%%%centimeter%('cm',%%%%0.01), %%%%meter%%%%%%(%'m',%%%%1),% %%%%kilometer%%('km',%1000)%

    %%%% %%%%String%abbreviation %%%%double%multiplier %%%% %%%%Unit(String%abbr,%double%mult)%{ %%%%%%%%this.abbreviation%=%abbr %%%%%%%%this.multiplier%=%mult% %%%%} %%%%String%toString()%{%abbreviation%}% }
  40. Unit enum and Distance class 51 enum$DistanceUnit%{ %%%%centimeter%('cm',%%%%0.01), %%%%meter%%%%%%(%'m',%%%%1),% %%%%kilometer%%('km',%1000)%

    %%%% %%%%String%abbreviation %%%%double%multiplier %%%% %%%%Unit(String%abbr,%double%mult)%{ %%%%%%%%this.abbreviation%=%abbr %%%%%%%%this.multiplier%=%mult% %%%%} %%%%String%toString()%{%abbreviation%}% } @TupleConstructor% class%Distance%{ %%%%double%amount% %%%%DistanceUnit%unit %%%%String%toString()%{% %%%%%%%%"$amount%$unit"% %%%%}% }
  41. Different techniques • To add dynamic methods or properties, there

    are several approaches at your disposal: • ExpandoMetaClass • custom MetaClass • Categories • Let’s have a look at the ExpandoMetaClass 52
  42. Using ExpandoMetaClass 53 Number.metaClass.getCm%=%{%f>% %%%%new%Distance(delegate,%Unit.centimeter)% } Number.metaClass.getM%=%{%f>% %%%%new%Distance(delegate,%Unit.meter)% } Number.metaClass.getKm%=%{%f>%

    %%%%new%Distance(delegate,%Unit.kilometer)% } 40.cm! 3.5.m 4.km Add that to integration.groovy ‘delegate’ is the current number Usage in your DSLs
  43. Distance okay, but speed? • For distance, we just added

    a property access after the number, but we now need to divide (‘div’) by the time 54 2.km/h
  44. Distance okay, but speed? • For distance, we just added

    a property access after the number, but we now need to divide (‘div’) by the time 54 2.km/h The div() method on Distance
  45. Distance okay, but speed? • For distance, we just added

    a property access after the number, but we now need to divide (‘div’) by the time 54 2.km/h The div() method on Distance An h duration instance in the binding
  46. First, let’s look at time 55 enum$TimeUnit%{ %%%%hour%%%%%%('h',%%%3600), %%%%minute%%%%('min',%%%60),% %%%%kilometer%('s',%%%%%%1)%

    %%%% %%%%String%abbreviation %%%%double%multiplier %%%% %%%%TimeUnit(String%abbr,%double%mult)%{ %%%%%%%%this.abbreviation%=%abbr %%%%%%%%this.multiplier%=%mult% %%%%} %%%%String%toString()%{%abbreviation%}% }
  47. First, let’s look at time 55 enum$TimeUnit%{ %%%%hour%%%%%%('h',%%%3600), %%%%minute%%%%('min',%%%60),% %%%%kilometer%('s',%%%%%%1)%

    %%%% %%%%String%abbreviation %%%%double%multiplier %%%% %%%%TimeUnit(String%abbr,%double%mult)%{ %%%%%%%%this.abbreviation%=%abbr %%%%%%%%this.multiplier%=%mult% %%%%} %%%%String%toString()%{%abbreviation%}% } @TupleConstructor% class%Duration%{ %%%%double%amount% %%%%TimeUnit%unit %%%%String%toString()%{% %%%%%%%%"$amount%$unit"% %%%%}% }
  48. Inject the ‘h’ hour constant in the binding 56 def)binding!=)new!Binding([

    !!!!robot:!new!Robot(), !!!!*:!Direction.values() !!!!!!!!!!!!.collectEntries!{ !!!!!!!!!!!!!!!![(it.name()):!it] !!!!!!!!!!!!}, !!!!h:!new!Duration(1,!TimeUnit.hour) ])
  49. Operator overloading • Currency amounts • 15.euros + 10.dollars •

    Distance handling • 10.km - 10.m • Workflow, concurrency • taskA | taskB & taskC • Credit an account • account << 10.dollars account += 10.dollars account.credit 10.dollars 58 a%+%b%%//%a.plus(b) a%f%b%%//%a.minus(b) a%*%b%%//%a.multiply(b) a%/%b%%//%a.div(b) a%%%b%%//%a.modulo(b) a%**%b%//%a.power(b) a%|%b%%//%a.or(b) a%&%b%%//%a.and(b) a%^%b%%//%a.xor(b) a[b]%%%//%a.getAt(b) a%<<%b%//%a.leftShift(b) a%>>%b%//%a.rightShift(b) +a%%%%%//%a.unaryPlus() fa%%%%%//%a.unaryMinus() ~a%%%%%//%a.bitwiseNegate()
  50. Operator overloading • Update the Distance class with a div()

    method following the naming convetion for operators 59 class%Distance%{ %%%%... %%%%Speed%div(Duration%t)%{ %%%%%%%%new%Speed(this,%t) %%%%} %%%%... }
  51. Operator overloading • Update the Distance class with a div()

    method following the naming convetion for operators 59 class%Distance%{ %%%%... %%%%Speed%div(Duration%t)%{ %%%%%%%%new%Speed(this,%t) %%%%} %%%%... } Optional return
  52. Equivalence of notation • Those two notations are actually equivalent:

    60 2.km/h 2.getKm().div(h) 㱻 This one might be slightly more verbose!
  53. Named parameters usage move!left,!at:!3.km/h Will call: def!take(Map!m,!Direction!q) 61 Named parameter

    Normal parameter All named parameters go into the map argument Positional parameters come afterwards
  54. Command chains • A grammar improvement in Groovy 1.8 allowing

    you to drop dots & parens when chaining method calls • an extended version of top-level statements like println • Less dots, less parens allow you to • write more readable business rules • in almost plain English sentences • (or any language, of course) 63
  55. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} //%zerofarg%methods%require%parens select%all%%unique()%from%names

    //%possible%with%an%odd%number%of%terms deploy%left%%arm %%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%) %%%%%(%%%%%%%%%%%).%%%%%%(%%%%) %%%%%(%%).%%%%(%%).%%%%(%%) %%%%%%(%%%).%%%%%%%%.%%%%(%%%%%) %%%%%%(%%%%). 68
  56. Playing it safe... • You have to think carefully about

    what DSL users are allowed to do with your DSL • Forbid things which are not allowed • leverage the JVM’s Security Managers • this might have an impact on performance • use a Secure AST compilation customizer • not so easy to think about all possible cases • avoid long running scripts with *Interrupt transformations 74
  57. Security Managers • Groovy is just a language leaving on

    the JVM, so you have access to the usual Security Managers mechanism • Nothing Groovy specific here • Please check the documentation on Security Managers and how to design policy files 75
  58. SecureASTCustomizer 76 def!secure!=!new!SecureASTCustomizer() secure.with!{ //!disallow!closure!creation !!!closuresAllowed!=!false! //!disallow!method!definitions !!!methodDefinitionAllowed!=!false! //!empty!white!list!=>!forbid!certain!imports !!!importsWhitelist!=![...]!

    !!!staticImportsWhitelist!=![...] //!only!allow!some!static!import !!!staticStarImportsWhitelist!=![...] //!language!tokens!allowed !!!!tokensWhitelist!=![...] //!types!allowed!to!be!used !!!constantTypesClassesWhiteList!=![...] //!classes!who!are!allowed!to!be!receivers!of!method!calls !!!receiversClassesWhiteList!=![...] } def!config!=!new!CompilerConfiguration() config.addCompilationCustomizers(secure) def!shell!=!new!GroovyShell(config)
  59. Controlling code execution • Your application may run user’s code

    • what if the code runs in infinite loops or for too long? • what if the code consumes too many resources? • 3 new transforms at your rescue • @ThreadInterrupt: adds Thread#isInterrupted checks so your executing thread stops when interrupted • @TimedInterrupt: adds checks in method and closure bodies to verify it’s run longer than expected • @ConditionalInterrupt: adds checks with your own conditional logic to break out from the user code 77
  60. @TimedInterrupt • InterruptedException thrown when checks indicate code ran longer

    than desired 79 @TimedInterrupt(10) import!groovy.transform.TimedInterrupt! ! while!(true)!{ !!!!move!left !!!!//!circle!forever }
  61. @ConditionalInterrupt • Specify your own condition to be inserted at

    the start of method and closure bodies • check for available resources, number of times run, etc. • Leverages closure annotation parameters from Groovy 1.8 80 @ConditionalInterrupt({$battery.level$<$O.1$}) import%groovy.transform.ConditionalInterrupt 100.times%{%%%% %%%%move%forward%at%10.km/h }
  62. Using compilation customizers • In our previous three examples, the

    usage of the interrupts were explicit, and users had to type them • if they want to deplete the battery of your robot, they won’t use interrupts, so you have to impose interrupts yourself • With compilation customizers you can inject those interrupts thanks to the ASTTransformationCustomizer 81
  63. Groovy Power!™ • A flexible and malleable syntax • scripts

    vs classes, optional typing, colons and parens • Groovy offers useful dynamic features for DSLs • operator overloading, ExpandoMetaClass • Can write almost plain natural language sentences • for readable, concise and expressive DSLs • Groovy DSLs are easy to integrate, and can be secured to run safely in your own sandbox 83
  64. Groovy Power!™ • A flexible and malleable syntax • scripts

    vs classes, optional typing, colons and parens • Groovy offers useful dynamic features for DSLs • operator overloading, ExpandoMetaClass • Can write almost plain natural language sentences • for readable, concise and expressive DSLs • Groovy DSLs are easy to integrate, and can be secured to run safely in your own sandbox 83 Groovy is a great fit for DSLs!
  65. And there’s more! • We haven’t dived into... • How

    to implement your own control structures with the help of closures • How to create Groovy « builders » • How to hijack the Groovy syntax to develop our own language extensions with AST Transformations • Source preprocessing for custom syntax • How to use the other dynamic metaprogramming techniques available • How to improve error reporting with customizers • IDE support with DSL descriptors (GDSL and DSLD) 84
  66. Thank you! Guillaume Laforge Head of Groovy Development Email: [email protected]

    Twitter: @glaforge Google+: http://gplus.to/glaforge Blog: http://glaforge.appspot.com 85
  67. Image credits • Pills: http://www.we-ew.com/wp-content/uploads/2011/01/plan-b-pills.jpg • Chains: http://2.bp.blogspot.com/-GXDVqUYSCa0/TVdBsON4tdI/AAAAAAAAAW4/EgJOUmAxB28/s1600/breaking-chains5_copy9611.jpg • Russian

    flag: http://good-wallpapers.com/pictures/4794/Russian%20Flag.jpg • Space odissey: http://dearjesus.files.wordpress.com/2010/04/2001_a_space_odyssey_1.jpg • HAL red: http://2.bp.blogspot.com/-yjsyPxUFicY/TcazwAltOaI/AAAAAAAAAho/GVT7wGhnrUM/s1600/2001-a-space-odyssey-HAL.jpg • Back in time: http://4.bp.blogspot.com/-Pt44Dk9J2EM/TrQx9YNmVcI/AAAAAAAAAk4/ivWw9Lja05k/s1600/clocky.jpg • USSR Space posters: http://www.flickr.com/photos/justinvg • Russian General: http://rickrozoff.files.wordpress.com/2012/02/general-nikolai-makarov.jpg • Rocket: http://blog.al.com/breaking/2009/03/soyuz_launch.jpg • Progress capsule: http://www.spacedaily.com/images/progress-ocean-desk-1024.jpg • Buran: http://www.buran.fr/mriya-antonov/Photos//050-Exhibition%20au%20Bourget%20avec%20Bourane-Airshow%20with%20Buran%20at%20Le%20Bourget-1134884.jpg • Man in space: http://vintagespace.files.wordpress.com/2010/11/voskhod-2_leonov.jpg • Sputnik 2: http://launiusr.files.wordpress.com/2010/06/sputnik2.jpg • Lunakod: http://www.astr.ua.edu/keel/space/lunakhod_moscow.jpg • Sandbox: http://www.turnbacktogod.com/wp-content/uploads/2008/09/sandbox.jpg • Repair: http://www.oneangels.com/wp-content/uploads/2012/03/repair1.jpg • Mars rover: http://wallpapers.free-review.net/wallpapers/49/Mars_rover%2C_Mars_-_03.jpg • Mars rover 2: http://www.universetoday.com/wp-content/uploads/2011/06/551038main_pia14156-43_946-710.jpg • Thumb: http://www.wpclipart.com/sign_language/thumbs_up_large.png.html • Night sky: http://www.aplf-planetariums.info/galeries/ciel_profond/2004-07-01-Voie_Lactee_Scorpion-Jean-Luc_PUGLIESI.jpg • Obama yes we can: http://www.dessinemoiunboulon.net/wp-content/uploads/2009/01/obama-yes-we-can_04-nov-08.jpg • Hook: http://winningware.com/blog/wp-content/uploads/2009/12/FishHookXSmall.jpg • HP 48 GX: http://calculators.torensma.net/files/images/hewlett-packard_hp-48g.jpg • Omer: http://www.irmin.com/wallpaper/TV/Homer%20Simpson%20Oh%20No.jpg • Cadenat: http://acsgsecurite.com/upl/site/cadenat.png 87