Namek Dev
a developer's log
NamekDev

From Kotlin to Java: moving back seeing all the flaws

April 5, 2017
From Kotlin to Java: moving back seeing all the flaws

In previous week I had to resign from using Kotlin in one of my game projects. By porting the code manually I can point out what I didn’t like about Kotlin. Let’s see few differences between Kotlin and Java.

Why port?

Libgdx enables us to build our games to HTML5 webapp through the Google Web Toolkit. Kotlin compiles directly to bytecode, while GWT works on top of Java to generate JavaScript. So, bytecode and Kotlin? No, won’t work.

It seems there appears something new on the horizon, it’s called Dragome but it’s too early to use it.

Manually?

There is beautiful functionality that translates Java directly to Kotlin. Most of the transpilation looks pretty good. Some comments are broken and constants are put into companion object without const  keyword. Few issues about interfaces or docs, too. However, transpilation is pretty awesome.

Any other way? No. There is no option. Unless, you’ll use an output of decompilation of generated bytecode. However, this stuff needs too much of manual cleaning, fixing and redefining:

  • lots of annotations (like @Metadata or @NotNull)
  • getters and setters instead of pure fields
  • are comments are lost
  • formatting is generated basing on formatter configuration

So, yeah. It’s a lot easier to copy-paste code and “fix” the syntax. Doing this, I rediscovered what I learned when porting the first way some time ago (those were Java classes that I further developed in Kotlin).

My dislikes on Kotlin

Bit shifting

Shifting some bits to the left is done using shl operator, not the << anymore. Why do we need this innovation?

object CollisionGroups {
    val CHARACTER: Long = 1
    val SOLDIER = (1 shl 1).toLong()
    val BULLET = (1 shl 2).toLong() //made of enemy
    val WALL = (1 shl 3).toLong()
    val DRAGON = (1 shl 4).toLong()
    val FIREBALL = (1 shl 5).toLong()
    val BURNING_AREA = (1 shl 6).toLong()
}

instead of:

public interface CollisionGroups {
    long CHARACTER = 1;
    long SOLDIER = 1 << 1;
    long BULLET = 1 << 2;
    long WALL = 1 << 3;
    long DRAGON = 1 << 4;
    long FIREBALL = 1 << 5;
    long BURNING_AREA = 1 << 6;
}

Looks like nothing disturbing. Well, look at this part of code from my serializer:

protected fun addRawShort(value: Short) {
    _buffer[_pos++] = (value.toInt() shr 8 and 0xFF).toByte()
    _buffer[_pos++] = (value.toInt() and 0xFF).toByte()
}

While it could look like this:

protected void addRawShort(short value) {
    _buffer[_pos++] = (byte) ((value >> 8) & 0xFF);
    _buffer[_pos++] = (byte) (value & 0xFF);
}

Still, nothing too fancy. However, I can’t stand seeing too much shr and shl mixed together. Operators based on symbols like >> or << are visually more clear to me.

No static finals to imitate constants

It’s pretty usual in Java to type this boring text to define some constant:

class SomeSuperClass {
    public static final int TYPE_OMG = 7;
}

In Kotlin I have to create a companion object to simply define some static things! The approach here is simple - classes have only the methods that are attached to instance. You want something static? Define such object, thus companion object.

I was little unlucky with this one because the official Java-Kotlin converter didn’t made it well and it wouldn’t compile. The converter forgot to put the const keyword as in below:

class SomeSuperClass {
  companion object {
    const val TYPE_OMG = 7
  }
}

Otherwise, I’m cool with it when I don’t try to call this from Java code. In Java it would be:

SomeSuperClass.companion.TYPE_OMG - language interopability pains me here!

using types for reflection cache

Please compare these two on your own:

AssetSystem::class.java ↔ AssetSystem.class

Then, type such things multiple times in a row as I do with artemis-odb. Oh, you know about AssetSystem::class? Well, this gives you not an instance of Class<>  but KClass<> . When a coding custom serializer - it does matter which type you choose because those are separate objects.

Overall syntax is shorter but this makes it less readable

Some syntax may look neat but here’s the interface implementation vs class extension:

class MoveByExecutor : TemporalOperation.TemporalExecutor<MoveByOp>

See the colon (:)? I don’t know whether the TemporalExecutor is a class or an interface! I have to visit the file to find out. In Java it would be either implements or extends which come obvious about the type.

Another one. Generics are little different - they’re not invariant anymore

override fun executorType(): Class<out Executor<out Operation>> {
    return MoveByExecutor::class.java
}

Look at the Executor. Now I’m back to Java equivalent:

@Override
public Class<? extends Executor> executorType() {
    return MoveByExecutor.class;
}

Just evaluate it on your own.

My, ooooh, my likes on Kotlin!

There are lots of course. But let’s point out a few.

Null safety

There’s not much to say. You don’t have this in Java. You can’t simply pass null if function argument doesn’t accept it by definition. Sometimes it is incovenient but most of all it catches errors just by converting Java code to Kotlin code and seeing what it has found about null safety.

Read about Null safety

Functional approach

What I did like - support for mapping arrays and such - it’s just easy to type. May not be something unusual comparing to other languages (especially functional ones) but it’s nice compared to Java 7!

val SpawnFlyDirections = arrayOf(
  Vector2(1f, -1f).nor(),
  Vector2(-1f, -1f).nor(),
  Vector2(-1f, 1f).nor(),
  Vector2(1f, 1f).nor()
)

// place those points around map circle
// assume: map center is placed on (0, 0)
val SpawnLandPoints = SpawnFlyDirections.map { dir ->
  Vector2(dir).scl(-(LogicalRadius - Assets.Soldier.ColliderRadius))
}

KDoc: Markdown-like comments for classes and methods

I was pretty much amazed by this one. No more writing HTML <ul><li></li><li></li></ul> just for bullet points, instead just use asterisk (the *) symbols preceeded with whitespace each in new line.

More to it, linking to classes and fields changed from Java’s:

  • {@link ClassName} to just [ClassName]
  • fields of external classes {@link ClassName#fieldName} to [ClassName.fieldName]
  • fields of the same classes from {@link #fieldName} to [fieldName]

More on KDoc here.

No redundancy for data-like classes

(psst, yeah, I know data class keyword but it’s not important here)

So, why not have this:

class DoThrowSoldierAction(
  val soldierId: Int,
  val playerId: Int,
  val dirX: Int,
  val dirY: Int
) : Event { }

instead of the Java boring equivalent:

public class DoThrowSoldierAction implements Event {
    public final int soldierId;
    public final int playerId;
    public final int dirX;
    public final int dirY;

    public DoThrowSoldierAction(int soldierId, int playerId, int dirX, int dirY) {
        this.soldierId = soldierId;
        this.playerId = playerId;
        this.dirX = dirX;
        this.dirY = dirY;
    }
}

It’s beautiful difference for small classes. One downside here - it’s worse when class has more constructors than one (of course, when argument default value doesn’t do job).

Summary

There is no perfect language in this world. Kotlin seems to be really interesting just by looking at these these features:

  • null safety
  • functional approach to data manipulation
  • introduces immutability (like in functional langs)
  • no semicolons (I mean it)
  • val and var keywords
  • neat lambdas (outer scope variables don’t have to be final like in Java)
  • destructuring (functional languages again)
  • compiles to JavaScript
  • (and it’s being developed to be able to compile into native code (Kotlin Native))

References

Artemis Entity Tracker, Daj Się Poznać, gamedev, Get Noticed 2017, java, kotlin
comments powered by Disqus