DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

100 Languages Speedrun: Episode 35: Groovy

JVM is a very powerful platform, but Java language is miserable. A bunch of alternatives emerged, Kotlin, Clojure, Scala, Groovy, and JRuby being the most popular ones.

If current trends continue, then in the next few years Kotlin might displace Java as the main JVM language.

But for this episode let's check a less popular contender, Groovy.

Hello, World!

// Hello world in Groovy
println("Hello, world!")
Enter fullscreen mode Exit fullscreen mode

Guess what it does?

$ groovy hello.groovy
Hello, world!
Enter fullscreen mode Exit fullscreen mode

Notice lack of nasty semicolons, and other boilerplate. Normal Java-style comments with // and /* ... */ are supported.

FizzBuzz

1.upto(100) {
  if (it % 15 == 0) {
    println("FizzBuzz")
  } else if (it % 5 == 0) {
    println("Buzz")
  } else if (it % 3 == 0) {
    println("Fizz")
  } else {
    println(it)
  }
}
Enter fullscreen mode Exit fullscreen mode

There's a bit of Ruby-inspired syntax with 1.upto(100) { ... }. There's a lot of other ways to loop, even Java-style for loops.

it is a default list iteration variable, which is a nice shortcut more languages could use.

Fibonacci

def fib(n) {
  if (n <= 2) {
    1
  } else {
    fib(n - 1) + fib(n - 2)
  }
}

for (i in 1..30) {
  println("fib(${i}) = ${fib(i)}")
}
Enter fullscreen mode Exit fullscreen mode

There's no need to declare types if you don't want to, and there's no need for extra return.

We have string interpolation with "${}". Can you imagine string interpolation used to be highly controversial? Even Python was resisting hard, and only finally saw the light in Python 3.6 in December 2016!

This example uses different style of looping. Ranges do the correct thing and 1..30 means 1 to 30 (not 1 to 29 as in some other languages).

Unicode

Just as all other JVM languages (except notably JRuby), Groovy can't do Unicode correctly:

println("Hello".length())
println("Źółw".length())
println("💩".length())
Enter fullscreen mode Exit fullscreen mode

It outputs completely wrong results:

$ groovy unicode.groovy
5
4
2
Enter fullscreen mode Exit fullscreen mode

JRuby pays high performance price for being correct in such cases.

Data Classes

Let's define a very simple data class Point to represent a point in 2D space. We want the class to have nice constructor, and to understand == and .toString(), but we really don't want to write all that boilerplate.

import groovy.transform.ToString
import groovy.transform.EqualsAndHashCode

@EqualsAndHashCode
@ToString(includeNames=true)
class Point {
  Double x
  Double y

  def length() {
    Math.sqrt(x * x + y * y)
  }
}

a = [1, 2, 3]
b = [1, 2, 3]
c = new Point(x: 30.0, y: 40.0)
d = new Point(x: 30.0, y: 40.0)

println(a == b)
println(c == d)
println(null == d)
println("len of ${c} is ${c.length()}")
Enter fullscreen mode Exit fullscreen mode

Which outputs:

$ groovy equality.groovy
true
true
false
len of Point(x:30.0, y:40.0) is 50.0
Enter fullscreen mode Exit fullscreen mode

This is definitely more verbose than Kotlin's data class, but still saves us on boilerplate.

Let's go over it:

  • @EqualsAndHashCode - it defines == and .hashCode() methods, so we can check if two points are equal
  • @ToString(includeNames=true) - it defines .toString() method, so we can print the point - annotations accept various arguments to customize their behavior, in this case we use includeNames=true
  • import groovy.transform.ToString etc. - it's always annoying to import what feels like it should be just part of the language
  • Double x and Double y - static typing is optional, we can say def x and def y instead to have dynamic typing
  • new Point(x: 30.0, y: 40.0) - constructor with keyword arguments was automatically provided by Groovy
  • null == d - it does not crash like in Java, just returns false

Operator Overloading

In one of oh so many terrible decisions Java made was banning operator overloading, so any code that uses any library-defined containers or mathematical objects looks completely unreadable. It's like creators of Java did everything they could to make programmer life maximally miserable on purpose.

Anyway, in Groovy it all works fine. Every operator corresponds to some special name, like plus method is called when you do +:

import groovy.transform.*

@EqualsAndHashCode
@ToString
class Point {
  Double x
  Double y

  def length() {
    Math.sqrt(x * x + y * y)
  }

  def plus(other) {
    new Point(x: x + other.x, y: y + other.y)
  }
}

a = new Point(x: 10, y: 40)
b = new Point(x: 20, y: -20)

println("${a} + ${b} == ${a+b}")
Enter fullscreen mode Exit fullscreen mode

Collections

Groovy makes it easy to work with collections:

s = "Java is a terrible language"

println(s.split(" ").collect{ w -> w.capitalize() }.join(" "))
println(s.split(" ").collect{ it.capitalize() }.join(" "))
println(s.split(" ")*.capitalize().join(" "))
Enter fullscreen mode Exit fullscreen mode
$ groovy collections.groovy
Java Is A Terrible Language
Java Is A Terrible Language
Java Is A Terrible Language
Enter fullscreen mode Exit fullscreen mode

One interesting shortcut is *. which calls a given method on every element of the collection.

Should you use Groovy?

It sure beats Java. Don't use Java.

A more interesting question is Kotlin vs Groovy. Of the main non-Java languages on the JVM, Clojure, JRuby, and Scala are attempting to do their own thing and definitely not trying to take on Java directly. Groovy and Kotlin both do. They're basically saying "if you even want to write Java, you should use us instead".

Kotlin seems to be a bit closer to Java semantics, with everything typed by default and smaller runtime, instead of optionally typed with a bit bigger runtime of Groovy. But to me it seems like minor differences - either of them provides an overwhelming readability and productivity advantage over the pile of shitty boilerplate that's Java.

Kotlin is definitely winning popularity contest in the JVM world right now, but you'll do fine using either of them. Or Clojure. Or JRuby. I'm a bit less sure about Scala.

Also do I mention that Java is shit often enough?

Code

All code examples for the series will be in this repository.

Code for the Groovy episode is available here.

Discussion (5)

Collapse
patricktingen profile image
Patrick Tingen • Edited on

I like these posts on programming languages. Most of them I have never heard of. Do you take suggestions btw? I'd like to see how Progress 4GL compares in this list. Progress (or "OpenEdge" which is its newer name) is a database + 4GL language that has been around since the eighties. It supports procedural style code but OO as well. It is mainly used for business application.

Wikipedia: en.wikipedia.org/wiki/OpenEdge_Adv...
A free and fully functional copy can be downloaded from their site: progress.com/openedge/classroom-ed...

(happy to assist)

Collapse
taw profile image
Tomasz Wegrzanowski Author

I only have a couple episodes planned at a time, so suggestions are welcome.
I've never heard of Progress 4GL. As I'm doing one of these a day, I mostly limit it to languages which I can install on OSX with one brew command, and which have enough documentation that I can google my way out of any problems. There's some languages (like PowerShell and SAS) that's been waiting on the list for long as it's some hassle to run them on a Mac.

Collapse
duncte123 profile image
Duncan

Groovy is horrible, so glad that I switched to kotlin.
Even java is more fun to write by comparison.

Collapse
taw profile image
Tomasz Wegrzanowski Author

I'm quite interested in some deeper discussion why many people prefer Kotlin to Groovy. I tried to find any posts about it, and couldn't really find any, and in my one day of experimentation, I didn't really find any serious issues with Groovy.

Collapse
duncte123 profile image
Duncan • Edited on

On a high level groovy does not have any issues correct, the languages is actually quite fun to work with.

Just things like def myInt = 1; will compile to Object myInt = 1;. Another thing is that it does not work well with java in the same project, I really had to hack around that.

Kotlin on the other hand works amazingly well with java. The better typing that kotlin has is also great.

Groovy also has a lot of weird stuff like "ls -hal".execute().text just executing shell commands, this feels very sketchy to me.

demonstration of executing console commands

Fun things that groovy has are no returns (you can probably guess how this becomes confusing if you just have a variable at the end of a function)

def aFunction() { "Hello world" }
Enter fullscreen mode Exit fullscreen mode

although kotlin does it better

fun aFunction() = "Hello world"
Enter fullscreen mode Exit fullscreen mode