31
Introduction to Groovy runtime metaprogramming and AST transforms by Marcin Grzejszczak TooMuchCoding blog

Introduction to Groovy runtime metaprogramming and AST transforms

Embed Size (px)

DESCRIPTION

Introduction to Groovy runtime metaprogramming and AST transforms - by Marcin Grzejszczak author of the http://toomuchcoding.blogspot.com blog. The sources can be found here Mercurial Bitbucket - https://bitbucket.org/gregorin1987/too-much-coding/src/e5ab7c69ab7b2796075fd6f087fbf31346aa2d2b/Groovy/ast/?at=default Git Github - https://github.com/marcingrzejszczak/too-much-coding/tree/master/Groovy/ast

Citation preview

Page 1: Introduction to Groovy runtime metaprogramming and AST transforms

Introduction to Groovy runtime metaprogramming and AST

transformsby Marcin GrzejszczakTooMuchCoding blog

Page 2: Introduction to Groovy runtime metaprogramming and AST transforms

Question

Integer getTimesTenOf(Integer number) {

return 10 * number;

}

assert 40 == getTimesTenOf(4)

How to calculate ten times a number?

Page 3: Introduction to Groovy runtime metaprogramming and AST transforms

Let’s invert the concept!

assert 40 == 4.tens

Page 4: Introduction to Groovy runtime metaprogramming and AST transforms

It can’t be done… Can it? public final class Integer ... {

// ...

}

Page 5: Introduction to Groovy runtime metaprogramming and AST transforms

Add that method!Integer.metaClass.getTimesTens = {

return 10 * delegate

}

assert 40 == 4.timesTen

Page 6: Introduction to Groovy runtime metaprogramming and AST transforms

Monkey patch

● Extend or modify the run-time code ● Do not alter the original source code ● Also known as duck punching and shaking

the bag

Page 7: Introduction to Groovy runtime metaprogramming and AST transforms

Classes with Groovypublic class Foo implements groovy.lang.GroovyObject

extends java.lang.Object {

}

Page 8: Introduction to Groovy runtime metaprogramming and AST transforms

GroovyObjectpublic interface GroovyObject {

Object invokeMethod(String name, Object args);

Object getProperty(String propertyName);

void setProperty(String propertyName, Object newValue);

MetaClass getMetaClass();

void setMetaClass(MetaClass metaClass);

}

Page 9: Introduction to Groovy runtime metaprogramming and AST transforms

Meta Object Protocol

● MetaObject is an object that manipulates, creates, describes, or implements other objects (including itself).

● Stored info includes base object's type, interface, class, methods etc. ● MetaObjects are examples of reflection concept● The Meta-Object-Protocol (MOP) is the collection of rules of how a request

for a method call is handled by the Groovy runtime system

Page 10: Introduction to Groovy runtime metaprogramming and AST transforms

MetaClass

MetaClass defines the behaviour of any given Groovy or Java class - ● The MetaClass interface has two parts:

○ Client API - via the extend MetaObjectProtocol interface ○ Contract with the Groovy runtime system.

● In general the compiler and Groovy runtime engine interact with methods on MetaClass class

● In general the MetaClass clients interact with the method defined by the MetaObjectProtocol interface

Page 11: Introduction to Groovy runtime metaprogramming and AST transforms

Expando● Kind of a dynamic bean. ● It will memorize

○ added properties○ added methods (from closures)

● Useful for ○ mocking○ when you don’t want to create a new class (you just want to record

behaviour)

Page 12: Introduction to Groovy runtime metaprogramming and AST transforms

Expandodef player = new Expando(name: 'Robert')

assert 'Robert' == player.name

player.surname = 'Lewandowski'

assert 'Lewandowski' == player.surname

player.presentYourself = {

return "Name: $name, Surname: $surname"

}

String result = player.presentYourself()

assert 'Name: Robert, Surname: Lewandowski' == result

Page 13: Introduction to Groovy runtime metaprogramming and AST transforms

ExpandoMetaClassA special implementation of a MetaClass that allows you to (using closures):

● dynamically add methods, ● constructors, ● properties and static methods

Page 14: Introduction to Groovy runtime metaprogramming and AST transforms

ExpandoMetaClass● ExpandoMetaClass - Borrowing Methods — Borrowing methods from other classes● ExpandoMetaClass - Constructors — Adding or overriding constructors● ExpandoMetaClass Domain-Specific Language● ExpandoMetaClass - Dynamic Method Names — Dynamically creating method names● ExpandoMetaClass - GroovyObject Methods — Overriding invokeMethod, getProperty and setProperty● ExpandoMetaClass - Interfaces — Adding methods on interfaces● ExpandoMetaClass - Methods — Adding or overriding instance methods● ExpandoMetaClass - Overriding static invokeMethod — Overriding invokeMethod for static methods● ExpandoMetaClass - Properties — Adding or overriding properties● ExpandoMetaClass - Runtime Discovery — Overriding invokeMethod for static methods● ExpandoMetaClass - Static Methods — Adding or overriding static methods

Page 15: Introduction to Groovy runtime metaprogramming and AST transforms

Add that method! - reminderInteger.metaClass.getTimesTen = {

return 10 * delegate

}

assert 40 == 4.timesTen

Page 16: Introduction to Groovy runtime metaprogramming and AST transforms

Add that method! - watch out!Integer.metaClass.getTimesTens = {

return 10 * delegate

}

Remember that :● You are mixing here a method to a class not to an object● In the same JVM all objects of that class will have that method added

to MetaClass! (You can image the downsides of this)● It’s safer to use categories - only a block of code will have those

methods mixed in

Page 17: Introduction to Groovy runtime metaprogramming and AST transforms

MOP - find that missing method!

Taken from Venkat's Programming Groovy 2

Page 18: Introduction to Groovy runtime metaprogramming and AST transforms

Metaprogramming in Groovy● Runtime

○ Categories○ Expando / MetaClass / ExpandoMetaClass

● Compile Time○ AST Transformations○ Extension Module

Page 19: Introduction to Groovy runtime metaprogramming and AST transforms

Runtime - drawbacks

● efficiency - finding if method exists● method / property missing - people start

asking questions how can that even compile● no IDE support

Page 20: Introduction to Groovy runtime metaprogramming and AST transforms

Abstract Syntax Tree● Representation of the abstract syntactic structure of

source code● Each node of the tree denotes a construct occurring in

the source code. ● The syntax is "abstract" in not representing every detail

appearing in the real syntax.

Page 21: Introduction to Groovy runtime metaprogramming and AST transforms

An abstract syntax tree for the following code for the Euclidean algorithm:

while b ≠ 0

if a > b

a = a − b

else

b = b − a

return a

Page 22: Introduction to Groovy runtime metaprogramming and AST transforms
Page 23: Introduction to Groovy runtime metaprogramming and AST transforms

AST Transformation

● Compile-time metaprogramming● Bytecode manipulation● Either global or local

○ Global in any compiler phase○ Local in a semantic analysis phase

or later

Page 24: Introduction to Groovy runtime metaprogramming and AST transforms

Did you know that…?Groovy compiler has 9 phases?

● Initialization● Parsing● Conversion● Semantic Analysis (important for Local AST transforms)● Canonicalization● Instruction Selection● Class Generation● Output● Finalization

Page 25: Introduction to Groovy runtime metaprogramming and AST transforms

AST Transformation annotations● @AnnotationCollector● @Externalize● @BaseScript● @Canonical● @CompileStatic● @TypeChecked● @ConditionalInterrupt● @EqualsAndHashcode● @Mixin● @Category● @Immutable● @Field● @IndexedProperty● @InheritConstructors● @Memoized● @PackageScope● @Synchronized

● @ThreadInterrupt● @TimedInterrupt● @ToString● @TupleConstructor● @WithReadLock● @WithWriteLock● @Delegate● @DelegatesTo● @Lazy● @Newify● @Singleton● @ASTTest● @AutoClone● @Commons● @Log● @Slf4j● @NotYetImplemented● @Grab● @GrabResolver

Page 27: Introduction to Groovy runtime metaprogramming and AST transforms

Local AST transforms for dummies

● Check the Guidebook● Define an annotation● Create an AST transform for the annotation● Build the transform

Page 28: Introduction to Groovy runtime metaprogramming and AST transforms
Page 29: Introduction to Groovy runtime metaprogramming and AST transforms

AST transforms - not that easy :(

● Creating implementation is not trivial○ Verify node○ Verify preconditions○ Make the implementation

● Use tools○ AstBuilder from string○ AstBuilder from code○ AstBuilder from spec

● The code might get really messy

Page 30: Introduction to Groovy runtime metaprogramming and AST transforms