introduction to groovy runtime metaprogramming and ast transforms

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

Upload: marcin-grzejszczak

Post on 25-May-2015

1.456 views

Category:

Technology


2 download

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

TRANSCRIPT

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