This document discusses various metaprogramming techniques in Groovy including:
- Meta Object Protocol (MOP) which allows modifying classes at runtime.
- Categories and mixins for adding methods to existing classes.
- Traits for reusable pieces of code with state.
- Extension modules for globally available extensions that can modify classes.
- AST transformations for compile-time modifications by transforming the AST.
- Over 70 built-in AST transformations like @ToString and @Immutable.
4. @aalmiray | andresalmiray.com
https://en.wikipedia.org/wiki/Metaprogramming
Metaprogramming is a programming technique in which
computer programs have the ability to treat other programs
as their data.
It means that a program can be designed to read, generate,
analyze or transform other programs, and even modify itself
while running.
In some cases, this allows programmers to minimize the
number of lines of code to express a solution, in turn
reducing development time. It also allows programs greater
flexibility to efficiently handle new situations without
recompilation.
8. @aalmiray | andresalmiray.com
Meta Object Protocol
• Every Class has a companion Metaclass
• Metaclasses provide additional behavior such as
• Properties
• Methods
• Modifications are visible only to Groovy.
9. Enhancing a Groovy class
1 class Person {
2 String name
3 }
4
5 Person.metaClass.greet = { s ->
6 "Hello $s, my name is $name"
7 }
8
9 p = new Person(name: 'Andres')
10 p.greet('Groovy')
11
12 // Hello Groovy, my name is Andres
10. Enhancing a Java class
1 String.metaClass.spongeBob = {
2 int i = 0
3 delegate.toCharArray()collect { c ->
4 (i++ % 2 != 0) ? c : c.toUpperCase()
5 }.join('')
6 }
7
8 'Metaprogramming is fun'.spongeBob()
9
10 // MeTaPrOgRaMmInG Is fUn
12. A catch-all option
1 class Foo {
2 Object methodMissing(String name, Object args) {
3 "What do you mean by ${name}(${args})?"
4 }
5 }
6
7 def foo = new Foo()
8 foo.say('Groovy')
9
10 // What do you mean by say([Groovy])?
13. A catch-all option
1 class Foo {
2 void propertyMissing(String name, Object arg) {
3 println "Can't assign a '$name' property to you!"
4 }
5
6 Object propertyMissing(String name) {
7 "You don't have a property named '$name'!"
8 }
9 }
10
11 def foo = new Foo()
12 println foo.id
13 foo.lang = 'Groovy'
14
15 // You don't have a property named 'id'!
16 // Can't assign a 'lang' property to you!
14. @aalmiray | andresalmiray.com
Does not Understand
• Method signatures must match the convention
• Object methodMissing(String, Object)
• void propertyMissing(String, Object)
• Object propertyMissing(String)
• May be implemented by both Groovy and Java classes
22. @aalmiray | andresalmiray.com
Extension Modules
• Like mixins but they are globally available.
• Can modify Groovy and Java classes.
• Provide instance and static methods.
• Can be type checked by the compiler.
• Require an additional resource (module descriptor).
23. Extension
1 package griffon.plugins.bcrypt;
2
3 public class BCryptExtension {
4 public static String encodeAsBcrypt(String self) {
5 return BCrypt.hashpw(self, BCrypt.gensalt());
6 }
7
8 public static String encodeAsBcrypt(String self, int
9 genSaltRound) {
10 return BCrypt.hashpw(self, BCrypt.gensalt(genSaltRound));
11 }
12 }
25. Using the Extension
1 String password = "my password"
2 // should give you a nice bcrypt hash
3 println password.encodeAsBcrypt()
26.
27. @aalmiray | andresalmiray.com
Compile Time
• Modify the generated byte code.
• Modifications are visible to Groovy and Java classes.
• Modifications can be type checked by the compiler.
28.
29.
30. @aalmiray | andresalmiray.com
AST Xforms
• Two flavors:
• Local
• Global
• Writing your own requires knowledge of compiler APIs,
AST type hierarchy, Groovy internals, your standard dark
magic ;-)
31. @aalmiray | andresalmiray.com
Local AST Xforms
• Require two types:
• An interface that defines the entry point.
• An AST forms that’s linked to the interface.
32. @ToString
1 @groovy.transform.ToString
2 class Person {
3 String firstName
4 String lastName
5 }
6
7 p = new Person(firstName: 'Jack', lastName: 'Nicholson')
8
9 // Person(Jack, Nicholson)
40. @aalmiray | andresalmiray.com
Global AST Xforms
• They only require the AST xform implementation.
• They are always available to all classes during the
compilation step.
42. @aalmiray | andresalmiray.com
Implementing AST Xforms
• Use of compiler APIs such as Expression, Statement,
ClassNode, etc.
• May use ASTBuilder to create expressions and
statements from text, code, builder nodes.
• May use macro methods to simplify expressions.
• Refer to core AST forms for hints and tricks.
43. @aalmiray | andresalmiray.com
Resources
• https://groovy-lang.org/metaprogramming.html
• https://www.slideshare.net/paulk_asert/groovy-transforms
• A History of the Groovy Programming Language
• (https://dl.acm.org/doi/pdf/10.1145/3386326)