« New to Swings? Sshhh... Don't Tell Anyone Sun's Secret! | Main | Why Would a Groovy Swing Programmer Need a Matisse-like GUI Builder? »

Late Binding is Swell, Late Typing is Groovy!

One of the major changes introduced late in the process of releasing Groovy 1.0 was the addition of the Meta-Object-Protocol or MOP. (Well, late is relative, considering it took 2-3 years to release Groovy 1.0 adding something 4 months from the end is late). One of the biggest features of the MOP is how it does the late bindings to the relevant Groovy methods based on type. This is best illisrtated by an example (who's output will be at the end of the post)...

class MOP_is_Groovy {
  void late(Float f) {println "Float!"}
  void late(Integer i) {println "Integer!"}
  void late(Number n) {println "Number?"}

  void earlyDef(def d) {late(d)}
  void earlyNumber(Number n) {late(n)}

t = new MOP_is_Groovy()
i = new Integer(2)
f = new Float(2)
n = new Long(2)

println "defs"

println "types"

What this example is doing is hiding the possible typing of the objects deeper into the class than a compiler would know at the surface level. If each of the calls to the early methods were instead direct calls to the late methods then the compiler could statically determine which of the particular late methods to call. But when hidden behind an intervening method the compiler cannot determine which one to call later because strictly speaking it doesn't know which one it will call later, because the method may be overridden by a sub class.

Groovy, however, whey applying a method call in a groovy script uses the MOP to look up the methods and finds one with the closest type at the time of invocation. When earlyDef is passed in an Integer, it uses the MOP to determine that it should call the Integer variant of late, and similarly with a Float. However, when a class is passed in that doesn't have an exact type match Groovy needs to find the signature that has the least distance from the passed in types. This example is rather tricky, because the implicit conversions for built in types takes precedence over trying to fit it into a parent type. A Long is closer to a Float than it is it's parent type of Number, simply because of these rules. If I had uses new types it would call the Number variant.

In order to be consistent Groovy applies the MOP even when the type at runtime can be constrained to a specific type, in this case lateNumberstill uses the MOP even though it knows that what is passed in must be a Number (it could also be an Integer or a Float as well). So how do you explicitly over-ride the MOPs choice of methods? Use Groovy's as operator to explicitly set the type at call time...

println "casted"
t.late(i as Number)

And as promised, the output of these scripts




Comments (2)


I didn't get the part where it prints "Float!" for a Long, though. Did something go wrong?

Danno Ferrin [TypeKey Profile Page]:

Nothing went wrong. This may not be the best example because there is some implicit type casting going on as a result of auto-unboxing. java.lang.Long isn't being treated as an object in type conversions but as the primitive type 'long', and the primitive type 'float' is considered to be a closer conversion than to the super class of the java.lang.Long boxed type, java.lang.Number.

So I am (out of lazyness) mixing in some boxixng/unboxing wonkiness. It may be wrong, but it is a matter of specification rather than correctness, because either one is valid (as long as it is specified).

Post a comment


This page contains a single entry from the blog posted on March 28, 2007 10:43 AM.

The previous post in this blog was New to Swings? Sshhh... Don't Tell Anyone Sun's Secret!.

The next post in this blog is Why Would a Groovy Swing Programmer Need a Matisse-like GUI Builder?.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33