Yesterday I blogged ten pleasant surprises with Groovy and Grails. Let me reiterate that overall, I am impressed. But there are a still a few issues that make JRuby a more promising alternative at present.
- Groovy classes are not open. I understand the reasons for this decision, but I want the productivity boost possible in a language where this is legal:
class Person { def firstName; } p = new Person(); class Person { def lastName; } p.lastName = 'Halloway'My example here is trivial, but the concept isn't. For more on both sides see here and here. - Grails is not written in Groovy! (For the most part.) I went looking for the implementation of the
chainmethod, and it was a whole Java class to itself. I am hoping that the Java bias is legacy, and that the Grails team is now more comfortable eating Groovy dog food. - The "optional static typing" argument is a red herring, until somebody produces some compelling examples. Groovy advocates point out that they have the best of both worlds--dynamic typing with static typing available on request where needed. This sounds good, and it may be good, but show me some significant examples. Better yet, articulate some rules of thumb for when to use dynamic typing, and when to use static typing, within a single Groovy project. This is a serious request, not flamebait. Instead of debating "static typing--yes or no?", let's debate "static typing--when?" in a language with a clean syntax for both.
Comments
i understand you are asking to mixin just by declaring the class again. however, the following is possible…
class Person extends Expando { def firstname; } p = new Person(); p.lastname = ‘Halloway’
also, the fact that Grails is not written in Groovy speaks volumes.
Hi Stuart,
To answer each of your worries in turn.
1) Open classes
In Groovy this would be implemented as:
class Person { def firstName } def p = new Person() p.metaClass.lastName = “Halloway”
println p.lastName
Since Groovy classes compile to Java classes which are effectively immutable, we have a different mechanism for doing what is effectively the same thing.
2) The usefulness of static typing
We find static typing very useful in certain circumstances of the implementation of Grails. Firstly we are able to implement more intelligent scaffolding more like Djangos because we have more type info available at runtime. Secondly we’re able to do neat things like command objects, which I haven’t seen in Rails (http://grails.org/Command+objects+and+Form+Validation)
Finally I still believe in certain cases static typing helps in readability and also from a tools perspective Groovy will be much easier for tool vendors to write things like code completion. However, I am in complete agreement that strong typing like in Java does get in the way, in this sense the fact that Groovy provides both is nice.
3) Grails being written in Java
This is a combination of things. Firstly it simply makes sense to write a lot of the plumbing in Java because the result is we get a far more performant framework. Rails might be proud of its 100% Rubyness, but the side effect is that it is dog slow. Grails is between 50 and 300% faster than Rails in our tests. Over time we have seen more and more of Grails being implemented in Groovy however, with all of our plugins now being written in Groovy (http://grails.org/Plugins) and the tag libraries (another feature missing from Rails) also written in Groovy. The split is about 80% Java and 20% Groovy at the moment. I imagine this becoming more 50/50 as time goes by.
Thanks for the feedback.
Graeme
Tag libraries aren’t exactly missing from Rails—just from the core. DRYML (http://hobocentral.net/manual/chapters/3_dryml.html ) provides a mechanism that is largely similar to that of tag libraries for Rails.
Groovy can, as Graeme has shown, modify the behaviour of Groovy and Java classes at run time. In fact Groovy has two ways of doing this. Firstly you can add or change the behaviour of a method in an arbitrary class (e.g. you can change the behaviour of java.lang.Object). Secondly you can change the behaviour of an arbitrary class but have that change seen in only one thread.
The first mechanism is very powerful but also very dangerous. In multithreaded environments this can lead to undesirable effects. Changing java.lang.Object’s toString method to call System.exit() is an extreme example of this danger:)
Whilst Ruby has thread support, I understand that it is not heavily used. It remains to be seen if an unconstrained ability to mutate classes is really a wise provision in languages, which run in naturally multithreaded environments like the JVM.
I’m surprised that you are surprised that Grails is mostly written in Java. Groovy is an adjunct to Java not a replacement for it. Because the syntax is pretty similar to Java and the Java<>Groovy impedance miss match is very small it’s perfectly natural to use a mixture of languages. If I want conciseness and expressiveness I’ll use Groovy if I want performance I’ll use Java and I’ll do this in the same program. Because it’s east to rewrite a Java class as a Groovy class and only slightly more difficult to rewrite a Groovy class as a Java class I often start in one language and move the implementation to the other. I also often subclass Java classes with groovy classes to get an object with a few high performance Java methods used by expressive Groovy methods.
Groovy is by no means perfect but I don’t think you will be able to really evaluate its strengths and weaknesses by comparing it to Ruby/JRuby. JRuby is a very good solution to the problem of running Ruby programs on the JVM (Thoughtwork’s Mingle is a good example of this). However, if you want to write TestNG unit tests in JRuby you have a problem – how are you going to do annotations? JRuby and Groovy are not essentially competitors and Dynamic languages on the JVM is not a zero sum game.
Shadowfield – Yes I’m very aware of DRYML. I demonstrated Grails’ tag libraries to its creator, Tom Locke a colleague and friend, months before he created or released any code for DRYML.
Tom tells me he didn’t copy Grails’ tag libs for DRYML, so I have no choice but to believe him, although I have my doubts ;-)
Stu,
You ask for some compelling examples of the use of static typing and for some guidelines as to when to use static and when to use dynamic typing. I can easily give you some examples you must decide if they are compelling.
My general advice to Groovy programmers is to always use dynamic typing except as follows:
If you are creating a Groovy object which is a subclass of a Java object and you want to override a method then use static typing for the return type and the parameters.
Similarly if you are implementing a Java interface then use static typing for the return type and parameters of the methods on the interface.
If you are creating an object which is to be used by Java code then use static typing for the return type and the parameters (it makes life easier for the Java programmer – who may well be you!).
Finally there are circumstances where you really do want to be sure that the type of the object you are dealing with is a particular type (i.e. you really care about the semantics). This has arisen in practice in a very large pure Groovy application developed by a financial institution. The do calculations using BigDecimal (Groovy uses BigDecimal rather than float/double as the default representation for real numbers). It was very important to them that there calculations were not “polluted” by non BigDecimal numbers. In their case near enough was not good enough. In this case I advised them to declare all thie BigDecimal values explicitly.
Note that it’s a very common misapprehension that static declarations speed up the execution of the program. Exactly the opposite is true. In a fully dynamic language knowing the type of a variable does not help you know the behaviour of the instance it contains. In addition you have to pass the type information along with the instance when passing the value as a parameter (because the instance could be a supertype of the type of the variable and could cause the wrong method to be selected).
Do you find any of these reasons compelling?
Stu,
did my comment help you understand the utility of optional typing in Groovy?
Perhaps a couple of concrete examples will help:
Let’s assume I want to subclass java.io.Writer. Writer has tree methods called write which take one parameter (int, String and char[]). Unless I can type the parameters in the subclass then I can’t do it directly and I have to use some kind of workround with varying degrees of suckyness.
Now let’s assume I have an object which implements java.util.List and I want to remove the ith element. If i us untyped then if I call remove(i) then I will invoke remove(Object) not remove(int) and I will get the wrong effect.
It is, of course, always possible to work round these problems with language which do not support typed variables. However I think it’s a positive advantage to not have to do so.
John: Your comments on optional typing make sense, but the advantages seem fairly modest. I would not swtich from one language to another to pick up just this capability, but I would use it if I had it.