Hello, world! A first look at Groovy
The first look at any programming language often begins with the traditional “hello world” program. Below is Java’s, for reference.
HelloWorld.java
1public class HelloWorld {
2 public static void main(String args[]) {
3 System.out.println("hello world");
4 }
5}
Groovy’s, on the other hand, looks like this:
HelloWorld.groovy
1class HelloWorld {
2 static def main(args) {
3 println("hello world")
4 }
5}
The claim, of course, is that Groovy clearly has less boilerplate code. The chief differences between these two are that
public
is implicit in Groovy.- types are optional. Thus, the omission of
String[]
in the argument declaration, and the use ofdef
instead ofvoid
. (Actually, here you can even get away with omittingdef
, sincestatic
is enough for the compiler to determine that you’re declaring something. But most people treatdef
as a return type and always specify it.) - semicolons are optional. The compiler puts them in wherever it pleases.
- there are a number of seemingly global functions introduced, such as
println
in this example. This is what we’ll be talking about today.
When I first saw the global println
, I assumed that either it was some
magical (read: contrived special case) alias to using that method on
System.out
, or that Groovy added support for top-level functions, something
Java’s sorely lacking. It turns out I was sorely wrong about the actual
implementation, which involves Groovy’s “metaclass” system. But that’s another
topic for another week.
The point here is that Groovy’s proponents claim that it reduces boilerplate by
making println
easier to get to. Of course, in plenty of environments,
writing to STDOUT is a perfectly fine way to accomplish logging. But in the
world of Java, it isn’t. (Yes, this is about to be a rant discussion
about Java logging. Feel free to skip the next section if you just care about
Groovy.)
Logging in Java
As a C/C++ programmer, when I first heard of the numerous logging “solutions” in Java, I was surprised. After all, how much is there for a logging library to do? All a logger does is take messages from the client code, coupled with log levels for each message, filters it according to level and possibly origin, adds contextual information (class, time, etc) and spits it into a file (or even just STDERR), right? There are plenty of well-documented and very functional systems for doing interesting things with the output of a process, including using syslog, performing log rotation, and teeing to external services. And it’s not like inter-process pipes are a poor solution — even Windows implements them well.
But noooo, it turns out each logging library tries to do everything itself. Writing to multiple files, rotating log files, communicating with external services. Everything. But there were apparently things people hated about each successive solution. To my understanding, it started with Java Logging. Then Apache gave us Log4j. Recently, we’ve had Slf4j and LogBack. Fortunately, each one is trying to be the be-all-and-end-all of Java logging solutions, and thus handily plugs into its predecessors to hijack them to use it instead.
My main experience is with Log4j and Slf4j. The only complaint I’ve ever encountered in real life, though, is rooted in library version conflicts, because it seems that a tonne of Java libraries feel the need to log stuff, even though these logs will never be usable to the client programmer, and only dilute the application logs if enabled. But because logging is controled at run-time (rather than at compile-time, which one would do for such debugging-related library logs in C/C++), the logging infastructure needed by every library needs to be fully functional.
Sometimes it’s nearly impossible to accomplish this. Perhaps your HTTP library depends on version 1.2.3 of some logging library, but your queue broker library depends on 2.4.1. With the default Java classpath mechanism, there’s no reliable way for the same library to exist with multiple versions at once. Sometimes, you can get away with just ignoring the version conflict, or finding a “happy medium” version which is sufficiently compatible that both libraries work when logging is disabled.
But say your HTTP library explicitly constructs a WidgetLogger
, which was
deprecated in version 1.8 and removed in 2.0. But 2.1 introduced
SproketLogger
, needed by your queue broker. Now it’s impossible, and you need
to resort to black classpath magic to make your program work, or switch to a
different HTTP or queue broker library (the latter is more common). From the
developer’s perspective, the problem lies in the logging library.
Where does this leave Groovy?
Despite Java’s logging conundrum, it’s still considered terrible style for any
production code to use STDOUT (ie, println
) unless it really is a
user-targetted terminal program. This is rarely the case.
What Groovy has done is made it easier for the programmer to do the wrong
thing. Not only that, but println(x)
is a lot less noticeable than
System.out.println(x)
, especially since it looks like a normal function
call. This so-called “reduction of boilerplate” does nothing for Real Programs,
which never use it, and serves only to obfuscate impropper use of standard
output.