Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a
Creative Commons Attr...
Upcoming SlideShare
Loading in …5
×

Groovy 3 and the new Groovy Meta Object Protocol in examples

3,880 views

Published on

Groovy3 and the new MOP are closing in! But the time of this talk the new MOP will not be done, but I will show some examples of how old Groovy code will look like transferred to the new MOP.

Published in: Technology

Groovy 3 and the new Groovy Meta Object Protocol in examples

  1. 1. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/1 Groovy 3 the new Meta Object Protocol in examples Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Jochen Theodorou, GoPivtoal Germany GmbH @JochenTheodorou
  2. 2. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/2 … in certainly not enough examples Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Jochen Theodorou, GoPivtoal Germany GmbH @JochenTheodorou
  3. 3. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/3 What cannot go forward goes backwards. Johann Wolfgang von Goethe (1749-1832), German Poet Translation by Jochen Theodorou “
  4. 4. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/4 Goals: ■ Metaclass as Persistent Collection and Realms ● Better multi threading performance ● Allowing different versions of metaclasses for same class ■ Only internal metaclasses ● no „extends MetaClassImpl“ any more, instead like ExpandoMetaClass for everything ● Delegation instead of Inheritance ■ MOP Methods ● Names and Signatures change to avoid conflicts with normal methods ● GroovyObject becomes a marker interface or is removed ● All methods then optional and in different variants ● No exception controlled MOP any more ■ Others ● All operators available for meta programmings ● Based on invokedynamic and ClassValue (Java 7 becomes minimum)
  5. 5. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/5 MOP Methods = in class defined methods to control MOP
  6. 6. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/6 Overview: ■ Uncached: ● Difficulty: I did hear of Groovy ● methodMissing, methodIntercept, propertyMissing, propertyIntercept ■ Cached 1: ● Difficulty: Me, want more. Now! ● cacheMethodMissing, cacheMethodIntercept, cachePropertyMissing, cachePropertyIntercept ■ Cached 2: ● Difficulty: I know what I do! Give me the full program! ● cacheMethodTarget, cachePropertyTarget
  7. 7. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/7 MOP Methods – A Groovy Builder Groovy 1 and Groovy 2
  8. 8. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/8 Groovy Builder in Groovy 1/2 class XmlBuilder { def out def methodMissing(String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } def xml = new XmlBuilder(out:System.out) xml.html { head { title "Hello World" } body { p "Welcome!" } } console output: <html><head><title>Hello World</title></head><body><p>Welcome! </p></body></html>
  9. 9. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/9 Groovy Builder in Groovy 1/2 class XmlBuilder { def out def methodMissing(String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } def xml = new XmlBuilder(out:System.out) xml.html { head { title "Hello World" } body { p "Welcome!" } } console output: <html><head><title>Hello World</title></head><body><p>Welcome! </p></body></html> called if no method can be found for call
  10. 10. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/10 Groovy Builder in Groovy 1/2 class XmlBuilder { def out def methodMissing(String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } def xml = new XmlBuilder(out:System.out) xml.html { head { title "Hello World" } body { p "Welcome!" } } console output: <html><head><title>Hello World</title></head><body><p>Welcome! </p></body></html> name = name of call args = arguments of call
  11. 11. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/11 Groovy Builder in Groovy 1/2 class XmlBuilder { def out def methodMissing(String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } //implcit return !//implcit return ! } def xml = new XmlBuilder(out:System.out) xml.html { head { title "Hello World" } body { p "Welcome!" } } console output: <html><head><title>Hello World</title></head><body><p>Welcome! </p></body></html>The result of the call is the result of methodMissing
  12. 12. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/12 MOP Methods – A Groovy Builder Groovy 3 Uncached
  13. 13. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/13 Groovy Builder in Groovy 3 - Uncached class XmlBuilder { def out MopResult methodMissing(String name, args) { out << "<$name>" If (args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" return MopResult.VOID } } def xml = new XmlBuilder(out:System.out) xml.html { head { title "Hello World" } body { p "Welcome!" } }
  14. 14. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/14 Groovy Builder uncached - before and after class XmlBuilder { def out def methodMissing (String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } class XmlBuilder { def out MopResult methodMissing (String name, args) { out << "<$name>" If (args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" return MopResult.VOID } }
  15. 15. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/15 Groovy Builder uncached - before and after class XmlBuilder { def out def methodMissing (String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } class XmlBuilder { def out MopResult methodMissing (String name, args) { out << "<$name>" If (args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" return MopResult.VOID } } MopResult contains the result of the call
  16. 16. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/16 Groovy Builder uncached - before and after class XmlBuilder { def out def methodMissing (String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } class XmlBuilder { def out MopResult methodMissing (String name, args) { out << "<$name>" If (args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" return MopResult.VOID } } it can also transport errors or that there is no result (VOID)
  17. 17. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/17 MOP Methods – A Groovy Builder Groovy 3 Cached return how to get a result, instead of the result itself
  18. 18. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/18 Ein Groovy Builder in Groovy 3 - Cached class XmlBuilder { def out def methodMissing (String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } class XmlBuilder { def out void cacheMethodMissing (GroovyCall call, String name) { call.chain {out << "<${name}>"} if(call[0].isAssignableTo(Closure)) { call[0].chain {it.delegate = this} call[0].execute() } else { call[0].execute "toString" } call.chain {out << "</${name}>"} } }
  19. 19. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/19 Ein Groovy Builder in Groovy 3 - Cached class XmlBuilder { def out def methodMissing (String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } class XmlBuilder { def out void cacheMethodMissing (GroovyCall call, String name) { call.chain {out << "<${name}>"} if(call[0].isAssignableTo(Closure)) { call[0].chain {it.delegate = this} call[0].execute() } else { call[0].execute "toString" } call.chain {out << "</${name}>"} } } since there is no result we return void
  20. 20. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/20 Ein Groovy Builder in Groovy 3 - Cached class XmlBuilder { def out def methodMissing (String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } class XmlBuilder { def out void cacheMethodMissing (GroovyCall call, String name) { call.chain {out << "<${name}>"} if(call[0].isAssignableTo(Closure)) { call[0].chain {it.delegate = this} call[0].execute() } else { call[0].execute "toString" } call.chain {out << "</${name}>"} } } GroovyCall is created for each uncached call
  21. 21. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/21 Ein Groovy Builder in Groovy 3 - Cached class XmlBuilder { def out def methodMissing (String name, args) { out << "<$name>" if(args[0] instanceof Closure) { args[0].delegate = this args[0].call() } else { out << args[0].toString() } out << "</$name>" } } class XmlBuilder { def out void cacheMethodMissing (GroovyCall call, String name) { call.chain {out << "<${name}>"} if(call[0].isAssignableTo(Closure)) { call[0].chain {it.delegate = this} call[0].execute() } else { call[0].execute "toString" } call.chain {out << "</${name}>"} } } No argument objects here, only their rutime classes
  22. 22. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/22 Some more details: ■ We provide a high-level API to let you express how to get to a result, not what the result is – This allows caching in the first place ■ The to be cached method called can go through cacheMethodMissing more than once. Reasons for that can be type changes for the arguments or the receiver ■ If you want to react different to different values of the same type, caching might be not for you. (example: provide the method to be called as additional argument instead)
  23. 23. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/23 MOP Methods – A Groovy Builder Groovy 3 MethodHandles
  24. 24. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/24 Ein Groovy Builder in Groovy 3 – MethodHandles class XmlBuilder { def out private final MethodHandle outField = LOOKUP.findGetter.... void cacheMethodTarget (GroovyCall call, String name) { call.chain( GroovyInvoker.bind(outField,"leftShift","<${name}>")) if (call.arg(0).isAsignableTo(Closure)) { call.arg(0).chain( GroovyInvoker.setProperty("delegate",this)) call.arg(0).execute() } else { call.arg(0).execute "toString" } call.chain( GroovyInvoker.bind(outField,"leftShift","</${name}>")) } }
  25. 25. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/25 Some Explanations: ■ Target is to produce a MethodHandle ■ GroovyCall high-level API is helping you here and can be mixed with MethodHandles ■ Of course the MethodHandles-API from Java7 is efficient and powerful, but also difficult to understand and handle – for example because types have to match exactly ■ Ultimately (and only for the most crazy people) we want to provide a way to give your own bootstrap method and then design yourself what you do with the call. This way you could for example completely emulate Javalogik and also speed (of course there is still an overhead through invokedynamic)
  26. 26. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/26 MOP Methods – Dynamic Finder Groovy 1 und Groovy 2
  27. 27. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/27 Dynamic Finder in Groovy 1/2 class GORM { // an array of dynamic methods that use regex def dynamicMethods = [...] def methodMissing (String name, args) { def method = dynamicMethods.find { it.match(name) } if (method) { GORM.metaClass."$name" = { Object[] varArgs -> method.invoke(delegate, name, varArgs) } return method.invoke(delegate, name, args) } else throw new MissingMethodException(name, delegate, args) } }
  28. 28. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/28 Dynamic Finder in Groovy 1/2 class GORM { // an array of dynamic methods that use regex def dynamicMethods = [...] def methodMissing (String name, args) { def method = dynamicMethods.find { it.match(name) } if (method) { GORM.metaClass."$name" = { Object[] varArgs -> method.invoke(delegate, name, varArgs) } return method.invoke(delegate, name, args) } else throw new MissingMethodException(name, delegate, args) } } adds a meta method to metaClass for each missing method
  29. 29. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/29 Dynamic Finder in Groovy 1/2 class GORM { // an array of dynamic methods that use regex def dynamicMethods = [...] def methodMissing (String name, args) { def method = dynamicMethods.find { it.match(name) } if (method) { GORM.metaClass."$name" = { Object[] varArgs -> method.invoke(delegate, name, varArgs) } return method.invoke(delegate, name, args) } else throw new MissingMethodException(name, delegate, args) } } makes the metaClass stay in memory
  30. 30. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/30 The metaclass is in Groovy 1 and 2 actually linked to an instance, but has to be saved in a global structure. That might use SoftReferences to avoid memory problems, still garbage collection doesn't like such actions.
  31. 31. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/31 MOP Methods – Dynamic Finder Groovy 3 Uncached
  32. 32. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/32 Dynamic Finder in Groovy 3 class GORM { // an array of dynamic methods that use regex def dynamicMethods = [...] MopResult methodMissing (String name, args) { def method = dynamicMethods.find { it.match(name) } if (method) { GORM.metaClass."$name" = { Object[] varArgs -> method.invoke(delegate, name, varArgs) } return MopResult.of (GroovyInvoker.invoke (method, delegate, name, args)) } else return MopResult.ERROR } }
  33. 33. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/33 Dynamic Finder in Groovy 3 class GORM { // an array of dynamic methods that use regex def dynamicMethods = [...] MopResult methodMissing (String name, args) { def method = dynamicMethods.find { it.match(name) } if (method) { GORM.metaClass."$name" = { Object[] varArgs -> method.invoke(delegate, name, varArgs) } return MopResult.of (GroovyInvoker.invoke (method, delegate, name, args)) } else return MopResult.ERROR } } makes the metaClass stay in memory
  34. 34. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/34 Dynamic Finder in Groovy 3 class GORM { // an array of dynamic methods that use regex def dynamicMethods = [...] MopResult methodMissing (String name, args) { def method = dynamicMethods.find { it.match(name) } if (method) { GORM.metaClass."$name" = { Object[] varArgs -> method.invoke(delegate, name, varArgs) } return MopResult.of (GroovyInvoker.invoke (method, delegate, name, args)) } else return MopResult.ERROR } } but not longer than the class GORM
  35. 35. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/35 MOP Methods – Dynamic Finder Groovy 3 Cached
  36. 36. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/36 Dynamic Finder in Groovy 3 class GORM { // an array of dynamic methods that use regex def dynamicMethods = [...] void cacheMethodMissing (GroovyCall call, String name) { def method = dynamicMethods.find { it.match(name) } if (method) { call.chain (method, delegate, name) } else call.error() } } metaClass stays unchanged
  37. 37. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/37 Metaclass Versions and Views
  38. 38. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/38 Recover old version of a metaclass class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 def oldMetaClass = A.metaClass.freeze() A.metaClass.foo = {->2} assert new A().foo() == 2 oldMetaClass.restore() assert new A().foo() == 1
  39. 39. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/39 Recover old version of a metaclass class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 def oldMetaClass = A.metaClass.freeze() A.metaClass.foo = {->2} assert new A().foo() == 2 oldMetaClass.restore() assert new A().foo() == 1 handler for the meta class Instead of the meta class itself
  40. 40. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/40 Recover old version of a metaclass class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 def oldMetaClass = A.metaClass.freeze() A.metaClass.foo = {->2} assert new A().foo() == 2 oldMetaClass.restore() assert new A().foo() == 1 make handler keeping current meta class version
  41. 41. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/41 Recover old version of a metaclass class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 def oldMetaClass = A.metaClass.freeze() A.metaClass.foo = {->2} assert new A().foo() == 2 oldMetaClass.restore() assert new A().foo() == 1 set meta method
  42. 42. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/42 Recover old version of a metaclass class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 def oldMetaClass = A.metaClass.freeze() A.metaClass.foo = {->2} assert new A().foo() == 2 oldMetaClass.restore() assert new A().foo() == 1 restore old metaclass version
  43. 43. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/43 Some explanations: ■ Before Groovy 3 we always mutate the metaclass ● Recovering an old state is difficult ● Isolating changes almost impossible ■ In Groovy 3 the metaclass is a persistent collection which you can reference by a handler ● Handler can be set to always give the actual meta class ● Or to “freeze” to keep the actual version and then maybe restore later In the long term this might actually allow to serialize meta class states
  44. 44. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/44 Usage of Realms class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 realm { A.metaClass.foo = {->2} assert new A().foo() == 2 } assert new A().foo() == 1
  45. 45. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/45 Usage of Realms class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 realm { A.metaClass.foo = {->2} assert new A().foo() == 2 } assert new A().foo() == 1 create sub realm
  46. 46. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/46 Usage of Realms class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 realm { A.metaClass.foo = {->2} assert new A().foo() == 2 } assert new A().foo() == 1 set new meta method
  47. 47. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/47 Usage of Realms class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 realm { A.metaClass.foo = {->2} assert new A().foo() == 2 } assert new A().foo() == 1only visible in subrealm
  48. 48. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/48 Usage of Realms class A{} A.metaClass.foo = {->1} assert new A().foo() == 1 realm { A.metaClass.foo = {->2} assert new A().foo() == 2 } // end of realm assert new A().foo() == 1 return to parent realm
  49. 49. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/49 Some Explanations: ■ A Realm is a set of metaclases separated from the normal program (or parent realm) at the point of call ■ Changes inside the Realm stay in the Realm and its subrealms ■ Exiting a Realm means to discard all changes done in the Realm Thought Usage: ● Libraries can isolate code and protect it from outside changes ● Lexicographic Categories
  50. 50. Unless otherwise indicated, these slides are © 2013-2014 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/50 And as always, there is by far not enough time :(

×