Groovy Metaprogramming for Dummies Darren Cruse (not a professional speaker: please no heckling or throwing of food per Groovy User Group Regulation 103a subsection e) Monday, June 7, 2010
Groovy Metaprogramming
for Dummies
Darren Cruse
(not a professional speaker: please no heckling or throwing of food per Groovy User Group Regulation 103a subsection e)
Monday, June 7, 2010
Meta Stuff(about the meta talk)
•Who am I?Once too good for “scripting”
Former Perl Nut
Recent Javascript Graduate
Improving Groovy Skills
Monday, June 7, 2010
Meta Stuff(about the meta talk)
•What’s this talk about?metaprogramming = “programming the program”
metaprogramming = what makes groovy really groovy!
Monday, June 7, 2010
Meta Stuff(about the meta talk)
• Who’s this talk for?
Ideally: Someone who’s seen a bit of groovy and aspires to get to the next level
Someone still unconvinced groovy’s power and productivity is sufficiently greater than java’s to merit learning a language with such a silly name.
(and you advanced guys feel free to dive in and help me out!)
Monday, June 7, 2010
Builders = Metaprogramming Magic
def builder = new StreamingMarkupBuilder()builder.encoding = 'UTF-8'def books = builder.bind { mkp.xmlDeclaration() namespaces << [meta:'http://meta/book/info'] books(count: 3) { book(id: 1) { title lang:'en', 'Groovy in Action' meta.isbn '1-932394-84-2' } book(id: 2) { title lang:'en', 'Groovy Programming' meta.isbn '0123725070' } book(id: 3) { title 'Groovy & Grails' comment << 'Not yet available.' } book(id: 4) { mkp.yieldUnescaped '<title>Griffon Guide</title>' } }}
Monday, June 7, 2010
Builders = Metaprogramming Magic
<?xml version="1.0" encoding="UTF-8"?><books xmlns:meta="http://meta/book/info" count="3"> <book id="1"> <title lang="en">Groovy in Action</title> <meta:isbn>1-932394-84-2</meta:isbn> </book> <book id="2"> <title lang="en">Groovy Programming</title> <meta:isbn>0123725070</meta:isbn> </book> <book id="3"> <title>Groovy & Grails</title> <!--Not yet available.--> </book> <book id="4"> <title>Griffon Guide</title> </book></books>
Monday, June 7, 2010
def builder = new StreamingMarkupBuilder()builder.encoding = 'UTF-8'def books = builder.bind { mkp.xmlDeclaration() namespaces << [meta:'http://meta/book/info'] books(count: 3) { book(id: 1) { title lang:'en', 'Groovy in Action' meta.isbn '1-932394-84-2' } book(id: 2) { title lang:'en', 'Groovy Programming' meta.isbn '0123725070' } book(id: 3) { title 'Groovy & Grails' comment << 'Not yet available.' } book(id: 4) { mkp.yieldUnescaped '<title>Griffon Guide</title>' } }}
println XmlUtil.serialize(books)
Builders = Metaprogramming Magic
<?xml version="1.0" encoding="UTF-8"?><books xmlns:meta="http://meta/book/info" count="3"> <book id="1"> <title lang="en">Groovy in Action</title> <meta:isbn>1-932394-84-2</meta:isbn> </book> <book id="2"> <title lang="en">Groovy Programming</title> <meta:isbn>0123725070</meta:isbn> </book> <book id="3"> <title>Groovy & Grails</title> <!--Not yet available.--> </book> <book id="4"> <title>Griffon Guide</title> </book></books>
Monday, June 7, 2010
book(id: 2) { title lang:'en', 'Groovy Programming' meta.isbn '0123725070'}
XML Builders = An alternative Syntax for XML
<book id="2"> <title lang="en">Groovy Programming</title> <meta:isbn>0123725070</meta:isbn></book>
Monday, June 7, 2010
But How?(is it code or is it data?)
Any sufficiently advanced technology is indistinguishable from magic.
Arthur C. Clarke,English physicist & science fiction author (1917 - )
def builder = new StreamingMarkupBuilder()builder.encoding = 'UTF-8'def books = builder.bind { mkp.xmlDeclaration() namespaces << [meta:'http://meta/book/info'] books(count: 3) { book(id: 1) { title lang:'en', 'Groovy in Action' meta.isbn '1-932394-84-2' } book(id: 2) { title lang:'en', 'Groovy Programming' meta.isbn '0123725070' } book(id: 3) { title 'Groovy & Grails' // & is converted to & comment << 'Not yet available.' } book(id: 4) { mkp.yieldUnescaped '<title>Griffon Guide</title>' } }}
println XmlUtil.serialize(books)
Monday, June 7, 2010
The Answer Lies in Groovy’s Nature As a Dynamic Language
(as distinguished from java)
compile time
Java
run time
compile time
Groovy
run time
Monday, June 7, 2010
Java Compilation
javasource
bytecode
Monday, June 7, 2010
Groovy Compilation
groovysource
bytecode
metaprogram
Monday, June 7, 2010
The Program Generated...
Evaluates Your Program At Runtime...
...it does so using a framework that is designed for you to plug into...
When you do so you are “programming the program”...
i.e. metaprogramming.
Monday, June 7, 2010
This framework is called the “Meta Object Protocol”
(“protocol” in the sense of an “api”)
MOPMonday, June 7, 2010
If you’re familiar with a framework like Struts...
This really isn’t that different:
Instead of mapping url requests to the code that handles them, you’re mapping actual method calls and property accesses to the code that handles them!
Instead of using struts-config.xml to do the mapping, you’re using actual code in the form of data structures called “meta classes”
The simplest and coolest of these is called the ExpandoMetaClass!
Monday, June 7, 2010
All Groovy Objects Implement...
public interface GroovyObject {
Object invokeMethod(String name, Object args);
Object getProperty(String propertyName);
void setProperty(String propertyName, Object newValue);
MetaClass getMetaClass();
void setMetaClass(MetaClass metaClass);}
(This the heartbeat of the MOP)
Monday, June 7, 2010
MetaClasses Implement these methods for a classand thereby define the behavior of the class.
Object invokeMethod(String name, Object args);
Object getProperty(String propertyName);
void setProperty(String propertyName, Object newValue);
The beauty of ExpandoMetaClass is that you can add methods and properties to classes simply by assigning
them - it expands indefinitely (like a Map).
Monday, June 7, 2010
So The Magic Is Revealed(dynamic dispatch and missing methods)
<?xml version="1.0" encoding="UTF-8"?><books xmlns:meta="http://meta/book/info" count="3"> <book id="1"> <title lang="en">Groovy in Action</title> <meta:isbn>1-932394-84-2</meta:isbn> </book> <book id="2"> <title lang="en">Groovy Programming</title> <meta:isbn>0123725070</meta:isbn> </book> <book id="3"> <title>Groovy & Grails</title> <!--Not yet available.--> </book> <book id="4"> <title>Griffon Guide</title> </book></books>
def builder = new StreamingMarkupBuilder()builder.encoding = 'UTF-8'def books = builder.bind { mkp.xmlDeclaration() namespaces << [meta:'http://meta/book/info'] books(count: 3) { book(id: 1) { title lang:'en', 'Groovy in Action' meta.isbn '1-932394-84-2' } book(id: 2) { title lang:'en', 'Groovy Programming' meta.isbn '0123725070' } book(id: 3) { title 'Groovy & Grails' // & is converted to & comment << 'Not yet available.' } book(id: 4) { mkp.yieldUnescaped '<title>Griffon Guide</title>' } }}
println XmlUtil.serialize(books)
Monday, June 7, 2010
When it comes to Groovy’s syntax...What you can write is fixed by the
parser (like most languages)...
but there’s lots of optional stuff
optional “()“, optional “;”, optional “[]” (sometimes)...
so much optional it sounds nuts!
but there’s a method to the madness.
Monday, June 7, 2010
Combining the MOP with Groovy’s loose syntax...
You can highjack the meaning behind what the evaluator thinks
are method or property calls
but which supericially look more “declarative” than imperative
more “what” than “how”
the result can be shorter and clearer than java
Monday, June 7, 2010
Grails uses this stuff a lot...It has a lot of these “domain specific languages” or
“DSL”s
but this talk is about groovy it’s not about grails
But grails is the best example of where these approaches are used all over the place to do amazing things with just a
little code...so this talk is about grails
DSL
But it’s notit’s about how grails does things under the covers
about how *groovy* does things under the covers
so this is a meta talk about grailsExactly (exact-o-mundo)
Monday, June 7, 2010
And DSLs aren’t the only thing
The combination of closures and metaclasses can allow much coolness including:
AOP
IOC
Memoization
RMI via REST
(well, at least the factory pattern)
(a fancy word for caching)
(how many acronyms you gonna use?)
(without the AOP)(coolness = productivity)
Monday, June 7, 2010
The preceding will be demonstrated with some delightful code examples.
But first...
Monday, June 7, 2010
A Review of Closures for Newbies...
A java assignment:int val = 3;
A java function:public int func(int a, int b) { return a + b;}
Or in Groovy:def val = 3
A groovy function:def func(a, b) { a + b}
Monday, June 7, 2010
A Review of Closures for Newbies...
def func = (a, b) { a + b}
Closures are anonymous functions that can be assigned as *values*...
From the previously slide you can *almost* guess the syntax:
Close! Above itʼs the variable that holds the name so itʼs on the left thatʼs correct. The wrong part is the parameters:
def func = { a, b -> a + b}
Groovyʼs syntax is nice because the “{“ and “}” clearly mark the “code block”.
Monday, June 7, 2010
A Review of Closures for Newbies...
def class Counter { int count
def increment = { count ++ }}
One more thing about closures - regarding scoping...
A closure defined in the lexical scope of other code can refer to itʼs variables. This surrounding code is the “owner”:
But when closures are assigned to other objects, thereʼs more to life than just the surrounding code - esp. note the delegate:
this: as in Java, this refers to the instance of the enclosing class where a Closure is definedowner : the enclosing object (this or a surrounding Closure)delegate : by default the same as owner, but changeable for example in a builder or ExpandoMetaClass
Monday, June 7, 2010
A Review of Closures for Newbies...
def postiveOnly(Closure c) { list.each { val -> if(val > 0) c.call(val) }}
Oh! And one more thing about closures...Groovy has syntactic sugar which allows a function taking a closure as itʼs final argument can be called with the closure passed after the functions closing paren:
Can be called like so:
postiveOnly { val -> println “$val is > 0” }
And lastly: the default parameter if none is specified is simply “it”:
postiveOnly { println “$it is > 0” }
Monday, June 7, 2010
Finally: some real metaprogramming...
String.metaClass.shout = { delegate.toUpperCase(); }println "Groovy".shout()
Add a method to a class:
And yes, you could even:
(but just because you can doesnʼt mean you will)
This just shows what a flexible and powerful language groovy is.
postiveOnly { println “$it is > 0” }
String.metaClass.toUpperCase = { delegate.toLowerCase(); }println "Groovy".toUpperCase()
A programming language for grownups.
(with a silly name)
Monday, June 7, 2010