« RailsConf 2008 Saturday Night Key Note: Kent Beck | Main | RIAs - The New Web UI »

July 31, 2008

Groovy 1.5: No Private for You!

No_soup

Considering Groovy for your next big project?  We did.  All things considered, it figured to be a safe choice given its Java pedigree. From the limited exposure I'd had to Groovy up until that point, it looked and felt remarkably familiar to Ruby (a good thing).  I had even heard you could cut & paste any amount of Java into a .groovy file and it would just work.  Depending on what 'work' actually means, this is mostly true. 

One of the small untruths about Groovy behaving 'just like Java' is worth serious consideration - especially if you want your .groovy code to become API-ready.

By API-ready, I mean:

  • Thoroughly documented
  • Safe to use
  • Intuitive
  • If at all possible, preserves backwards compatibility when making API changes
As of Groovy 1.5, according to this JIRA ticket, Groovy intentionally ignores the private visibility modifier.  Consider this (pulled directly from the JIRA ticket):
 

def s = "12" def chars = s.value s.value = "ABCD" assert !chars.is(s.value) assert s == "AB" s.count=3 assert s == "ABC" s.offset = 1 assert s == "BCD" def s2 = "0123" s = s2.substring(0,2) assert s.value.is(s2.value) s2.value = "ABCD" assert s2 == "ABCD" assert s == "01"


Kind of reminds me of the former U.S. President Bill Clinton's grand court testimony where he perjures himself while arguing the exact meaning of the word "is".  Bill split hairs - here, we seem to be splitting Strings.  

Oddly, Strings s and s2 seem to be mutable through direct access to their private properties.  So, why is this?  Short answer: Closures. 

Groovy closures need access to the method and class properties in which they find themselves declared (their lexical context). These variables are part of the closure's scope.  In fact, this is the essence of what a closure actually is.

Closures are said to be 'bound' to the variables in their scope.  This is true, even if the closure instance is later passed out of the class in which it was originally declared.  The following, pulled directly from http://docs.codehaus.org/display/GROOVY/Closures+-+Formal+Definition illustrates this:
 

public class A {

private int member = 20; private String method() { return "hello"; } def publicMethod (String name_){ def localVar = member + 5; def localVar2 = "Parameter: ${name_}"; return { println "${member} ${name_} ${localVar} ${localVar2} ${method()}" } } } A sample = new A(); def closureVar = sample.publicMethod("Xavier"); closureVar();


The above code will print:
 

20 Xavier 25 Parameter: Xavier hello

All of this gives us new found power and flexibility.  But it also presents the Groovy implementers with a problem.

For this to work, the Groovy compiler and Meta Object Protocol (MOP) impl must have access to private members at both compile-time and runtime, respectively.  Remember, Groovy compiles to .class files and runs in the JRE like any other Java.  

With Java, I try to Javadoc all public and protected methods, especially if I intend my code to be API-ready.  To be pragmatic, private and package-protected class members are often left undocumented since there was less danger in their accidental misuse. They were, after all, private

Not so with Groovy. 

Looking forward, the only viable solution, it seems, will eventually result in past and future Groovy library incompatibilities (read, 'breaking change') either in the compiler or the MOP.  This is a fair concern for current and would-be Groovy adopters.  For this reason, Jochen Theodorou, Groovy's Tech Lead, wants to defer a 'fix' until 2.0, when such a change will more readily be accepted.  It also gives them some time to get it exactly right.  

My suggestion?  The Groovy team should talk with the JRuby guys.  They got it right with Ruby.  Perhaps there's something the Groovy team could learn.

Until then, to all Groovy API writers, consider yourselves warned.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83455a82969e200e553e3931b8834

Listed below are links to weblogs that reference Groovy 1.5: No Private for You!:

Comments

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment