Sorry, no podcast this week because I'm at the Dynamic Languages World Conference, where yesterday I managed to sit in on a Groovy Tutorial. Groovy, in case you're not aware, is "an agile and dynamic language for the Java Virtual Machine which builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk".

Groovy

I'm not writing this article to portray Ruby in a negative light, I love Ruby. However, there were a few scoops of syntactic sugar which were contained in groovy which I thought were worth sharing.

Working with hashes (Maps)

1
2
3
4
5
6
def name = ["first_name":"Gregg", "last_name":"Pollack"]
println name["first_name"]
>> Gregg

name.first_name
>> Gregg

Sugar: You can automatically access the hash keys as attributes just using .
Sugar: Some people might say that using : is simpler then =>
Sugar: Think about this as respect to mock objects, instead of:

1
2
3
user = mock('User')
user.stub!(:save).and_return true 
user.stub!(:destroy).and_return false

you could have


user = ["save":true, "destroy":false]

that's hawt

Closures

1
2
3
def say_hello = { println "hello" }
say_hello()
>> "hello"

To do the same thing in Ruby:

1
2
say_hello = lambda { puts "hello" }
say_hello.call

Sugar: Kinda nice that you don't have to use lambda in Groovy.
Sugar: You also don't have to use ".call", you just use ().

1
2
[1,2,3].each { print it }
>> 123

Sugar: In a closure, if you don't specify a parameter name, "it" is used. As opposed to Ruby:

1
2
[1,2,3].each { |it| print it }
>> 123

Why do we have to specify the name of the parameter? It'd be nice to have a default like "it".

Working with arrays

1
2
["gregg", "pollack"]*.toUpperCase()
>> ["GREGG", "POLLACK"]

Sugar: They have an operator for invoking methods on each item, the equivalent in Ruby:

1
2
["Gregg", "Pollack"].collect(&:upcase)
>> ["GREGG", "POLLACK"]

Just as good, but it's kinda neat they have an operator for that.

Fetching attributes of arrays

1
2
3
4
5
6
7
name1 = ["first_name":"Gregg", "last_name":"Pollack"]
name2 = ["first_name":"Jason", "last_name":"Seifer"]

names = [name1, name2]

names.first_name
>> ["Gregg", "Jason"]

Sugar: Check that out, if you call for an attribute on an array, it will look for those attributes on the objects inside the array. This got me thinking, what happens if you call for an attribute that doesn't exist.

1
2
names.middle_name
>> [null, null]

hah... rad.. no error, just doesn't have that property. This could be sweat for an array of different types of objects. Now in Ruby:

1
2
3
4
5
6
7
name1 = {:first_name => "Gregg", :last_name => "Pollack"}
name2 = {:first_name => "Jason", :last_name => "Seifer"}

names = [name1, name2]

names.collect {|name| name[:first_name] }
>> ["Gregg", "Jason"]

Hmm... I wonder if we can shorten that

1
2
names.collect(&:first_name)
>> NoMethodError: undefined method `first_name' for {:last_name=>"Pollack", :first_name=>"Gregg"}:Hash

Nope.. that's right, we don't want to call the method, we want to look up the value based on the key. Darn.

They can define the ++

Sugar: I know there's some good reason why we can define all the normal operators (ex. +, -) but not ++. Groovy can define ++, and I'm kinda jealous. I miss ++.

Vlogging and Railsconf

I stole my wife’s Flip Video for this trip, so I decided to try my hand at doing some Video Blogging. I’ll be trying to post an update every day for the next crazy week here in Germany, and then back at Railsconf.

This first video isn’t very educational, FYI, but over the next few days as Steven and I run into Speakers we’ll be getting many interviews where we ask “Give us your talk in 30 seconds”.

If you want to catch all the videos feel free to subscribe to my Vimeo RSS Feed.

If you’re coming to Railsconf please do say hi. Here’s what I’ll be doing:


  • Friday, 7:40 PM – 8:00 PMRuby Hero Awards Ceremony Before DHH’s keynote we’ll be giving out awards to people in our community who deserve some recognition.

  • Friday, 7:59 PM – We will premiere FOUR NEW RAILS ENVY VIDEOS before each keynote starting with DHHs. This time around we invited Five Runs Developer Adam Keys to join us in the madness.

  • Friday, 9:00 PM – 10:00 PMPodcast Meetup If you can’t make our talk earlier in the day, have additional questions from the talk, or just want to meet other people who are passionate about Podcasting, come out to our birds of a feather.

The videos we show at Railsconf will be posted here on the blog on Tuesday

AddThis Social Bookmark Button Tags: Groovy Railsconf Ruby ruby  | permalink


Comments

Leave a response

Mike BreenMay 27, 2008 @ 12:49 PM

“Sugar: Some people might say that using : is simpler then =>”

I could be wrong but I think this is implemented in Ruby 1.9?


Don PetersenMay 27, 2008 @ 01:55 PM

Second item as well, except for a minor difference: http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9#l10


mikongMay 27, 2008 @ 02:02 PM

Yep, using colon for the hash syntax is supported in Ruby 1.9.


Mat SchafferMay 27, 2008 @ 02:51 PM

@mike not exactly the same as this syntax, but close (and less characters)

http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9#l6


Matt AimonettiMay 27, 2008 @ 03:06 PM

Groovy:

user = [“save”:true, “destroy”:false]

Ruby (depending on your mocking framework)

user = mock_model(User, :save => true, :destroy => false)

Good syntax comparison, thanks.

-Matt


Scott BeckerMay 27, 2008 @ 03:10 PM

I believe Mike is right about : syntax for declaring hashes being in 1.9

Also, if you want dot notation for retrieving hash values, it’s easy to add: http://pastie.caboo.se/204188


Paul BarryMay 27, 2008 @ 03:13 PM

Gregg,

If you want to access values in a Hash like a method call, you make that happen with method_missing, but the problem is the syntax is ambiguous. What if your hash has a key that is named the same as the name of a method on hash?


Mike McKinneyMay 27, 2008 @ 03:13 PM

Groovy is, well, groovy… we can always patch Hash and Array to get some of the above though. Is Ruby coming full circle and starting to take features from languages it inspired? :)


Zoran RilakMay 27, 2008 @ 04:21 PM

names.middle_name

[null, null]

Well, this at least promises some good fun with mistyped method names which silently return null. Or with names typed correctly, but with objects in the array that are of the wrong class. Me, I am all for language catching my mistakes during run-time, and if I feel like it, I can always override method_missing, thus claiming that I do know what I am doing :)


Geoffrey GrosenbachMay 27, 2008 @ 05:45 PM

There’s no need to use method_missing to access Hash keys as methods. The standard OpenStruct class will do this for you.

require 'ostruct'
my_hash = OpenStruct.new(:a => 1, :b => 2)
my_hash.a
# => 1
my_hash.a = 8


steMay 28, 2008 @ 05:00 AM

I wouldn’t want any of this sugar in Ruby…

Hashes: 1.9 has the new syntax {firstname: “Gregg”, lastname: “Pollack”} which translates to { :firstname => “Gregg”, :lastname => “Pollack”}. You get the hash.key trick with openstructs, as Geoffrey showed.

Closures: in ruby parenthesis are optional, so sayhello() is just the same thing as sayhello; instead, you can use say_hello[] I don’t like Groovy’s implicit “it”: why forgo consistency just to save 4 keystrokes? And in return you get the most non-descriptive variable name ever!

Arrays: the []*.method() thing is just terrible: an operator which is just a shortcut for the collect() method?? I find ruby much more flexible (and consistent).

Fetching attributes: like Zoran said. And names.first_name just stinks :-)


Dax HuibertsMay 28, 2008 @ 08:42 AM

The [“gregg”, “pollack”]*.toUpperCase() is really awesome. I’ve had this idea to have something like that for a while now, my idea was with using a syntax something like [“gregg”, “pollack”]:toUpperCase() Groovy sure does some nice neat AND pretty readable tricks.


Clemens KoflerMay 28, 2008 @ 09:02 AM

As far as I remember, Ruby 1.9 will also provide the possibility to substitute lambda with ->. my_closure = lambda { puts “hi” } would optionally become my_closure = -> { puts “hi” }


mikongMay 28, 2008 @ 12:30 PM

I prefer Ruby’s collect over Groovy’s array operator.

But I think the ‘it’ default in closures is kinda nice.

Btw, Dave wrote a recent article in the PragDave blog about a new lambda syntax in Ruby 1.9.


ThorbenMay 28, 2008 @ 08:18 PM

I’m pretty unsure about which portions of Groovy I like and which not, but I even if I really liked this “it” block default at first hand, I think the idea is not really useful. When would one use it? Maybe for each? Something like:

array.each {puts it.size}

looks nice, but

array.each {it.upcase!}

looks not nice anymore, because it violates the “natural language” experience. And when the default is a good one, only for a few cases, my oppinion is, that it might be a better idea to stick with the current need to explicitly name the blocks parameter. The usecases are just to varying that it’s hard to find a smart name for the default block variable.

The []* thing is cool but I can live with collect, too.

But the first item on your list, the “def bla = {}” closure notation is a cool idea. It’s not saving you a ton of keystrokes but it feels very precise and expressive to me. The -> substitution of 1.9 doesn’t.


Dierk KönigMay 29, 2008 @ 04:10 AM

Hi Gregg, thanx for posting this blog entry. It was great to have you at my “Groovy in a day” workshop at DLW and I love your blog!

Anyway, I’d like to clarify some of the misconceptions in the comments (that are totally understandable if you come from Ruby). 1) x.y is not calling method y on object x. It is accessing the property y (by default this will call the method x.getY()). Instead, x.y() would be a method call. 2) Pretty similar to Ruby, Groovy has a missingMethod() concept and additionally a missingProperty(). 3) In Groovy, you have optional typing and the IDE will do type inference for you whenever possible. So about the ‘mistyping’ issue that Zoran mentioned, Groovy is in a much better position to catch those typos even before runtime, i.e. right at coding time! 4) About the GPath vs. collect{}: Yes, collect{} is equivalent but think about code like employees.address.town.name that collects from all employees all addresses and all town objects that they refer to and then all names of those. BTW: you can have of course any kind of filter right inside the path, e.g. findAll{} the Groovy equivalent of Ruby’s select{}. 5) The differences in Ruby and Groovy are not so much in the syntax anyway. They are in the runtime system. Groovy is designed to alleviate the pains of Java (the language). For example, all the objects in 4) are typically implemented in Java without knowing anything about Groovy or GPath. They may even be EJBs.

Finally, I’d like to add that when programming Groovy I also miss a number of things from my old Ruby days, most notably the quick startup time (the JVM still needs more than a second to start).


Daniel RoopMay 29, 2008 @ 08:17 AM

Good to see Groovy getting some play at the dynamic language conference. My experience with Groovy has been great unfortunately they don’t have a killer web framework like Rails, Merb, Django, or Seaside. There is grails, but it is a far cry from the quality that the other dynamic language frameworks give you.

Anyone interested in Groovy should know they just did a release that gave a huge bump to performance, and if you are looking for a dynamic language on the JVM, and need to use JVM features, Groovy is definitely the way to go, as JYthon and JRuby are not quite as mature in the Java integrations area.


ShadowfiendMay 29, 2008 @ 03:41 PM

Let’s not forget that we basically got the ‘it’ syntax for closures with the Methodphitamine at http://jicksta.com/articles/2007/08/04/the-methodphitamine


Mario AquinoMay 30, 2008 @ 07:20 AM

These are great examples. I find it useful to learn how other languages streamline common problems because it teaches me to think beyond the limitations of what I am using. It’s tempting to look at comparisons between two things as similar as Ruby and Groovy and infer an endorsement of one over the other, but it doesn’t have to be that way at all. Both languages have their strengths and continue to refine themselves by incorporating genuinely good ideas that can save us time and make us happy.


Stephen CelisJune 02, 2008 @ 12:13 AM

Symbol.class_eval do
  def to_proc
    proc { |o, *r| o.respond_to?(self) ? o.__send__(self, *r) : o[self, *r] || o[self.to_s, *r] }
  end
end

>> names &:first_name
=> [“Gregg”, “Jason”]


Jochen "blackdrag" TheodorouJune 02, 2008 @ 08:08 AM

I should probably clear a misunderstanding here with names.first_name, true in this case using an invalid attribute will cause returning null, so you could get [null,null]. But that is not the general case. That is how a map behaves in Groovy. For example [:].foo, which is basically creating an empty Map and then tries to get the value for the key “foo”. Since the map is empty it will return null. If that is disturbing you, then you can go and change the meta class for LinkedHashMap. It is just the the default for a LinkedHashMap in Java and Groovy didn’t change that. If you do “some String”.foo, then it will most probably throw a MissingPropertyException, since a String has usually no foo property. Well unless you added that property of course.

Then about the “it” parameter in closures. True, it is not very descriptive, it is not thought to be descriptive. If you don’t like that, then just don’t use it! You can always do: array.each {aString -> aString.upcase!()}. Well, that would be if strings where mutable in Groovy and there would be a upcase! method.


theIntuitionistJune 05, 2008 @ 11:21 PM

Great post. Interesting that meek little javascript can handle the first to points. The dot syntax i particularly find enjoyable…


Sorry, comments are closed for this Post, but feel free to email Gregg & Jason with your input. We'd love to hear it.