It is written for anyone familiar with Groovy or Kotlin and might be especially relevant if you are considering moving from Groovy to Kotlin. Hopefully, it can be interesting for non-Groovy and non-Kotlin people as well.
Please note that this is not intended to be a thorough comparison or overview of the languages. The only differences mentioned are those which I came across while transforming Groovy code to Kotlin.
Activity Tracker is a proof-of-concept plugin for IntelliJ IDEs to track and record user activity. It keeps all the data locally so you can see and control what is being logged.
IntelliJ plugins are usually written in Java with a bit of xml configs and IntelliJ platform Java API. Activity Tracker is not like that at all. In the first place, it mostly ignores standard xml configuration and uses LivePlugin Groovy API instead. From a plugin point of view this means that in addition to standard Java APIs it has to interface with LivePlugin Groovy API. Secondly, Activity Tracker was itself written in Groovy.
Writing plugins in Groovy is not a common practice. At the time the main motivation for me was to use a programming language more exciting than Java 6. These days IntelliJ uses Java 8 and Kotlin is “officially approved” language for writing plugins. So migrating from Groovy to Kotlin was not only about having fun but also about moving to standard technology.
No ‘new’ keyword
Unlike Groovy (and probably most JVM languages) there is no
new keyword in Kotlin.
To create an instance of a class you can just use the class name with constructor parameters.
No implicit narrowing/widening for numbers
Unlike Groovy (and probably most JVM languages) there is no implicit narrowing/widening conversion for numbers in Kotlin.
That is if you have a variable of type
Long you cannot assign
Int value to it and vice versa.
Even though this might seem strange,
it makes perfect sense because
Long classes are not subtypes of each other.
The same applies to
Considering how subtle and difficult it can be to find implicit conversion bugs
this is probably a good design.
(In case you were wondering about the silent number underflow/overflow, it is still there. Works the same way as in Java.)
Closure type parameters
In Groovy types and type parameters are optional.
You can skip types all together or specify them when you feel like doing it.
I found it useful to always add types to libraries and other APIs which might be heavily used from other code.
It works fine except for the
Closure<V> type which has a type parameter only for its return value.
To be fair, there is
ClosureParams annotation to specify types for closure inputs, but it’s too painful to use.
In Kotlin, closures (aka lambdas) have type parameters for inputs and output as you would expect.
“With” vs “run” and “apply”
One of the interesting features in Groovy is the
.with function defined on the
It takes a closure and executes it with
this set to the target object.
The result of
.with function is the value of the last expression in closure.
This can be useful for calling a bunch of methods on an object which doesn’t have a fluent API.
Confusingly, Kotlin has
with function which does exactly the same thing except that it cannot be called on the object itself.
So to replace Groovy
.with in Kotlin there is a
In addition, there is the
.apply function in Kotlin which is like
.run but returns a target object.
This is useful for building object trees and avoiding
it as the last expression in each closure.
“Modifying” immutable objects
Both Groovy and Kotlin can define value-objects classes, i.e.
a class with immutable fields and implicitly defined equality and hash code methods.
In Groovy it’s a class with
@Immutable annotation, in Kotlin
data class definition.
One of the things you might want to do with value-object is copy it into new object
changing one or more fields.
Even though the underlying implementation is different, from the user point of view Groovy and Kotlin code looks similar.
Groovy getters and setters
When referencing getters/setters from Groovy code you can pretend you’re using a public field.
So instead of Java-style getter
o.getFoo(), you can use
And instead of setter
o.setFoo("bar"), you can do
o.foo = "bar".
Kotlin also has groovy getters/setters, although for instance methods only.
Method names with spaces
Both Groovy and Kotlin allow method names with spaces. This might sound like a strange feature but it’s great for naming unit-tests so that you don’t have to choose between camel case, underscores or mixing both.
Another less practical but much more exciting question is whether any string can be a method name. For Groovy the answer is “yes”. Kotlin seems to be more restrictive.
Almost optional “return”
In Groovy the last expression in function/closure is its return value.
You can use
return keyword to return from a function earlier, otherwise it’s entirely optional.
In Kotlin this is more complex.
Functions must have the
return keyword while lambdas cannot use
The result of the last expression in lambda is the value that lambda will return.
return in lambda means returning from the enclosing method.
There must be good reasons behind this design in Kotlin
but why the last expression in functions needs the
return keyword is a mystery for me.
In practice, I had no problems with it except when transforming Kotlin lambdas
into methods and the other way round because the code has to be modified to add/remove
Getting Class object
Kotlin has its own reflection classes, i.e. in addition to
java.lang.Class there is
This makes sense because Kotlin has language features which do not exist in Java.
(For example, you might want to check using reflection if the function argument is optional.)
In Groovy, as far as I know, it’s not possible to check using reflection whether a function argument is optional or not. Probably, analyzing Groovy AST is the way to do it.
Groovy has quite a few “helper” methods which are automatically “added” to Java core classes.
withWriterAppend() method in
which simplifies appending to a text file using
In Kotlin there are also quite a few “helper” methods.
In particular for IO operations, in
kotlin.io.FileReadWrite there is
It does almost the right thing except that there is no option to make writer appendable
so reproducing Groovy behaviour is somewhat verbose.
Enhanced Collections and Maps
In Groovy there are few functions in the
DefaultGroovyMethods class which are automatically added to all collection classes.
collectEntries() function takes a closure and, assuming the closure returns
two-element arrays, puts them into a map with the first element as an entry key and second element as its value.
sort() function which takes a closure and returns a sorted collection or even a sorted map.
Kotlin has many similar functions available on collections and maps. There are few subtle differences though.
Similar to Groovy
collectEntries() Kotlin has
associateBy() function but it’s only available on collections, not on maps.
This makes it harder to convert one map into another.
Another example is
sortBy() function which in Kotlin exists only on collections and not maps.
(Note that except for a few differences, the code below is almost identical.)
Same class in different class loaders
On JVM class loaders work somewhat like “namespaces”. For example, if you load exactly the same bytecode for a class in two different class loaders, then instances of the class won’t be assignable between the class loaders.
In Groovy this is still true but since Groovy is an optionally typed language, you can skip types and use objects from another class loader calling methods dynamically. This is not a feature you would use every day but it can be useful.
Extending Groovy interfaces/classes in Kotlin
If you plan to use Groovy API from Kotlin, be aware that it doesn’t work very well at the moment.
Basically, the Kotlin compiler doesn’t see method implementations of
groovy.lang.GroovyObject generated by Groovy.
The only workaround I found is to manually implement these methods in Kotlin. If you know the answer, I’ll be grateful if you could reply to this question on Kotlin forum.
Kotlin was created few years after Groovy and borrowed some features from it so when switching from Groovy, Kotlin feels like “a language I almost know”.
Being statically typed, Kotlin might have a bit more “resistance” than Groovy. On the other hand, it seems to be more suitable for writing “big legacy enterprise projects”.
If you expected an opinion about which language is better, sorry there won’t be one. Both Groovy and Kotlin are good.
To conclude, here is the final code snippet showing strategically designed Kotlin core libraries: