www.flickr.com
Michael Kovacs' photos More of Michael Kovacs' photos
Recommend Me Cable Car Software logo

Thursday, May 10, 2007

JavaOne 2007 Day 3 - My groovy redux

I still remember the first time I was exposed to groovy. James Strachan stood on stage (I think it was 2003 or 2004) and with his very smooth and soothing voice dazzled everyone in the room with this new language that allowed you to get more done with less. In the period since that time groovy has had its ups and downs but lately it really seems to be coming of age since there's finally a release (1.0 was released in January of this year), there's the grails project, and the popularity of ruby and rails has at least raised the awareness of dynamic scripting languages to new levels. For java developers that haven't made the venture outside the confines of Java it appears now is as good a time as any to put a new weapon to your arsenal. Groovy is certainly a natural choice for many java developers that don't wish to learn a new API with ruby though there's quite a bit of the groovy API that extends java that appears to be at least partially inspired by ruby.

Today I attended Rod Cope's "Advanced Groovy" talk. So while I'd never written a line of groovy until today (I copied Rod's numerous examples for today's post) I felt up to the task of attending an "advanced" talk based on the level of most talks at JavaOne. It turned out I was right, as Rod spewed out code example after code example I felt quite at home with a few minor syntax differences that I will say are less "beautiful" than ruby but that's probably because I'm used to ruby now. But you could take any ruby developer, give them groovy and they would have no problems working with it based on the examples I saw in today's talk.

Let's look at some of the advanced features from Rod's examples:

Safe navigation - Allows safe traversal without getting NPEs and avoid doing null checks. When you call the property with "?" if anything in the chain is null the result is null.
people = ['rod' : ['age' : 36, 'height' : "5'9"]]
people.rod.age
-> 36
people?.joe?.age
-> null

Expando - a dynamic etch-a-sketch object that you can add methods and properties to on the fly
import groovy.util.Expando

rod = new Expando(name: 'Rod', age: 36)
rod.drinkWater = {num -> num.times { println "yummy" }}

print rod.age
-> 36
rod.drinkwater(2)
-> yummy
-> yummy

Template engines - A closure as template engine
t = {p -> "${p.name} is ${p.age()}" }
rod = new Person(name: 'Rod', age: 36)
println t(rod)

He also mentioned the existence of a GStringTemplateEngine. groovy.text.GStringTemplateEngine

Default parameters - just like ruby it supports default param values in method signatures

Single object iteration/identity. You can iterate over any object whether a collection or not. If it's not a collection you'll get back the object itself once in the block.
currentCustomer.employees['joe'].manager.secretary.each { it.bonus = 1000 }

With identity it's a way to have an implicit object set in the block. I'm not really clear on why this is such a big win at the moment.
currentCustomer.employees['joe'].manager.secretary.identity { 
println "salary = $salary" } <- same as saying secretary.salary

Currying - This is the process of using functions to manufacture other functions.
First a groovy example:
c1 = {a, b -> a + b}
c2 = c1.curry("Hi ") result = c2 = {b -> "Hi " + b}

Now let's see the same thing in ruby for folks that have never heard of currying before. The following code isn't mine it's taken from the the ruby quiz site.
require "curry"

scale = lambda { |size, object| object * size }
puts "3 scaleded to a size of 10 is #{scale[10, 3]}." # 30
puts

# curry some functions
double = scale.curry(2)
triple = scale.curry(3)
halve = scale.curry(0.5)

puts "4 doubled is #{double[4]}." # 8
puts "1 tripled is #{triple[1]}." # 3
puts "Half of 10 is #{halve[10]}." # 5.0


Dynamic language extensions - mixins. Of all the things that were shown the implementation of mixins made me cringe because you have to create a new class and then pollute your implementation code that uses the mixin with the "use" method. The ruby way is seamless and much more elegant to me but the groovy way is arguably a little safer because it's so explicit and you'd always know that you're dealing with mixed in implementation. Still, I don't like it :-)
class PropertiesHelper 
{
public static List getProperyNames(Object bean)
{
def methodNames = bean.class.methods.name.findAll { it.startsWith('get') }
def goodNames = methodNames - ['getMetaClass', 'getClass', 'getProperty']
def propertyNames = goodNames.sort().collect {
// "getName" -> "n" + "ame" -> "name"
it[3].toLowerCase() + it[4..-1]
}
return propertyNames
}
}

rod = new Person(firstName: 'Rod', lastName: 'Cope')
use(PropertiesHelper) {
for (prop in rod.propertyNames) {
println "${prop} = ${rod[prop]}"
}
}
-> firstName = Rod
-> lastName = Cope

Method aliasing
def p = System.out.&println
p('hi')

def doSomething(method) { method('dog') }
doSomething(p)
-> dog

After these simple examples Rod broke into a couple more complex examples that really showed the power of groovy and to me rivals DHH's video that made RoR so attractive to so many people.

Demo of xml-rpc
First start up a server
import groovy.net.xmlrpc.*

server = new XMLRPCServer()
server.testme = {name -> "$name is cool"}
server.startServer(new ServerSocket(9047))
go

Then create and run the client code
import groovy.net.xmlrpc.*

server = new XMLRPCServerProxy('http://localhost:9047)
println server.testme("Groovy")
go
Groovy is cool


Going back to the server let's add a new method to our service:
server.multiply = {it * 7}
go

Back to client, let's call it:
println server.multiply(3)
go
21

No reboots were needed in the above example code which is impressive

Next up was the ActiveX demo using http://danadler.com/jacob (Java API to COM)

import org.codehaus.groovy.scriptom.ActiveXProxy

excel = new ActiveXProxy("Excel.Application")
excel.visible = true
go

This opens excel on your machine

book = excel.workbooks.add()
go

Creates a new workbook in your opened excel instance
sheet = book.activesheet
go

Selects the first sheet in the workbook

He then proceeded to add data to the sheet programmatically, create charts and add formulas (this code isn't complete as I wasn't able to keep up with this section)
a1 = sheet.range('a1'); a2 = sheet.range('a2')
co = sheet.chartobjects.add(50,50,400,200)
go

After that he demonstrated the SwingBuilder and updated the excel spreadsheet via that UI

swing = new groovy.swing.SwingBuilder()
mybutton = swing.button(text: 'click me')
mybutton.actionPerformed = {
a1.value = new Random().nextFloat() * 500
chart.export('graphname.gif)
mybutton.icon = new javax.swing.ImageIcon('graphname.gif')
}

frame = swing.Frame(title: "The frame")
frame.show()

The above code shows the swing GUI and when you click the button the chart is updated both in excel and in the button that you've just clicked. The speed was fast with no noticeable slowness.

A couple final examples that were thrown in at the end
"cmd /c dir".execute().text -> execute a system process
Thread.start { any code } -> firing off a thread, this is just like ruby


It's great to see groovy finally coming into its own. Performance isn't bad and will only get better with optimization and for java devs that want to get into scripting or a ruby dev that needs to work in java and can't use jruby groovy's a really comfortable choice for all but the most religious ruby zealots :-)

Comments:

Post a Comment





<< Home

This page is powered by Blogger. Isn't yours?