Hello, world! A first look at Groovy

2013-10-06 in groovy java
Real programmers don't use `println`

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 of def instead of void. (Actually, here you can even get away with omitting def, since static is enough for the compiler to determine that you’re declaring something. But most people treat def 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.