Before I get into some issues I have with it, I guess I should note that it isn't ALL bad. Namely, they did a great job of making (mostly) seamless Java and Groovy integration possible... in BOTH directions. This is the 1 thing I wish JRuby would borrow from Groovy. What is the problem you ask? Well, with Groovy, you compile down to classes, and the resulting class is more or less exactly how you would expect it to work. That is, you can construct the object from Java directly, then call methods directly on it, exactly as you defined in your Groovy code. If you specified types, you will have access to those type declarations from Java. This is really good if you have an existing code base you want to integrate with. If you are starting an application from scratch with no dependencies, well, you might as well just stick with JRuby or Ruby (or whatever inferior language you like), since you can control whether integrating with your language from the Java end is a big deal. I played a TINY bit with Rhino, and they seem to have a similar type if integration possible, but Groovy seemed a lot cleaner... with Rhino you have to compile the class to a given object or interface... so the code itself doesn't really have a definition of the type in this case. Seemed like a bit of a hack to me, but if you are primarily using it from the JavaScript side, it is really a non-issue. Oh, and I decompiled the results of all 3 of these languages (Rhino, JRuby and Groovy), and Groovy seemed to add the lease baggage in the code, but it still had baggage.
Also... if you are a big fan of static typing, then Groovy will be a good transition to dynamic typing because you can fall back on static typing whenever you want. Personally, I see no reason to, but I am one who loves dynamic typing.
Now some bad things. Perhaps as a direct consequence of the apparent design goal to integrate seamlessly in both directions with Java, the language feels very... inconsistent. They TRY to do things in a nice dynamic way, but then fall short in some cases that I think Ruby shines in. This leading to my biggest gripe... the distinction between fields and methods. If you are going to support fields of varying scope, you essentially can't have the kind of clean design you have in Ruby. What do I mean by this? Well, let's look at an example.
In Ruby, if you have a property named "property" then you would define it as such:
attr_accessor :property
Which is equivalent to:
def property()
@property
end
def property=(value)
@property = value
end
So what is going on here? Well... we still have the distinction of fields and methods, but in Ruby, your fields are ALWAYS private. You can't make them public, so when you call a method, it will never be ambiguous with accessing a field. This means, invoking a method with no arguments, you can just drop the parenthesis because they are redundant. In fact, you can even drop them when there ARE arguments, as long as it doesn't make it ambiguous in conjunction with other method calls or whatever. I think this makes Ruby as clean as it is, and makes it really look like you are reading English... almost.
What about Groovy though? Well, they support a similar paradigm. Defining the same property is 1 line as well, but it looks like this:
def property
And it is essentially equivalent to creating getProperty() and setProperty(value). BUT! The consequence of seamless integration with Java means you can't drop the parenthesis in every method case. They too support dropping them when there are arguments, and it doesn't make it ambiguous, except when there are no arguments and it isn't a getter. Thus, in Ruby you could have "stream.close" but in Groovy it would have to be "stream.close()". This may seem minor, but every time I have to add those parens in Groovy, I'm reminded that Ruby's grammar feels so much more internally consistent.
I guess I wrote a lot about that, but for some reason that minor detail really irks me. Before I just end with only a single gripe, I better add a couple more for good measure. I haven't tried nested classes in Ruby yet (though I've read they are possible), but Groovy definitely doesn't support them, at least not now. I think this is something they will eventually get to, but as it stands, this is a major limitation. This seriously cuts short the "seamless integration" with Java that I feel is one of the significant strengths of Groovy. Not much more I can say about that, but maybe it's also because it is getting late and I am tired.
One more issue? Null. Groovy tried so hard to be like Ruby, but they missed yet another thing that I really like about Ruby. In Ruby, nil (Java and Groovy's null) is an object, just like any other object. What does this mean? Well, null pointer exceptions... no such thing. Instead they become a method missing error. This was a very cool concept to me the first time I saw it. I'm not sure if it allows significantly more concise code, but it does seem to pretty up the code, at least to me. A list of method calls as conditionals is a lot easier for me to parse than a mix of == and method conditionals. Visually, calling methods makes each condition a single entity, unlike with an == or != conditional. For example:
if connection != null && !connection.is_connected
vs
if !connection.nil? && !connection.connected?
Which brings me to another point that I won't go into too much details... but being able to add question marks and exclamation points to my method names has got me wishing I could do it in every language. Beyond cutting a couple characters from the method length, they allow you to add meta info about the method that is visible at a glance... such as question mark for asking a boolean question, and exclamation for indicating state will be changed (which are essentially the Ruby standards for their usage).
Ok, I have ranted enough. I haven't proofread this, because it is late. If anyone happens to read this, just enjoy or hate it as it is.
Mike
1 comment:
Nice post, One ruby thing i like to do instead of if !connection.nil? && connection.something i just do if connection && connection.something .
The nil evaluates to false and I think it looks cleaner.
Post a Comment