Kotlin - Decompiling Null safety operators - Part I

Using Java Decompilers to understand null safety operators in Kotlin

Posted on February 14, 2018

We were recently writing some code using Kotlin programming language. After finishing the task, one of our friends glanced at the code and quipped, "Is question mark a first class citizen in Kotlin?". We took a step back and looked at the code dispassionately for a second and couldn't stop smiling. Please take a look at this code snippet in Kotlin.


	var tower = resultMap[code.trim()]
	tower?.occurences = value
	var weight:Int? = resultMap[code.trim()]?.weight
	nestedTower?.subTowers?.add(Tower(code.trim()))
	

								

You will notice a number of question mark (?) operators used here. Kotlin, the new language on the JVM, is getting popular with null safety operators being one of the reasons. The question-mark(?) operator also known as the safe navigation operator is not entirely new to programming languages. It's a commonly used one in languages like Groovy, C# etc., for a long time. Kotlin introduces this safety operator and extends it with a couple of more operators in the safety front.

Kotlin


To being with, let's understand the difference between the two types of declarations in Kotlin as shown below.

					
	var anInt:Int = 10
	var anotherInt:Int? = 20						
						
				

For the Java-only eyes, the declaration of anotherInt is bound to bring your brows together. anInt is a normal integer variable. anotherInt is also an integer variable declared using Int?. Int? means, an integer value or null. So you can now assign null to anotherInt like this.

					
     anotherInt = null
						
				

anInt cannot be assigned to null, however. So Int? can be read as either integer or null.

Decompiler speaks

Let's take the following Kotlin code written in Types.kt file and compile it.

	
	fun main(arg:Array){
		var anInt:Int = 10
		var anotherInt:Int? = 20
		println(anotherInt)
		anotherInt = null
		println(anotherInt)
	}
					
				

We get TypesKt.class that you want to decompile. Let's use JDPro in http://www.javadecompilers.com/. Here's what the decompiler gives us.

 
				
public final class TypesKt { 
   public static final void main(@org.jetbrains.annotations.NotNull 
   String[] arg) {
     int anInt = 10;
     Integer anotherInt = Integer.valueOf(20);
     System.out.println(anInt);
     System.out.println(anotherInt);
     anotherInt = (Integer)null;
     System.out.println(anotherInt);
  }
}				
							
				

So, the Kotlin compiler merely treates anotherInt? as a reference data-type, by using the wrapper class, Integer. Hmm! That's interesting. You will also notice that, since Kotlin is very strict about null-safety it injects @NotNull annotation to the command-line arguments arg. How about a safety operator on a reference data type like say a String?. Let's add these lines to the main function in Kotlin and see what we get.

	
	var normalString:String = null
	var safeString:String? = null
	println(normalString)
	println(safeString)
						
				

Compiling this code will report an error that says,

error: null can not be a value of a non-null type String
var normalString:String = null

Kotlin, just doesn't allow null values even on reference types declared in the normal fashion. Remember, in Java the following line of code compiles without any error.

						
					String normalString = null;		
						

Decompiler speaks

Let's decompile the following code in Kotlin and see what it has to say.

						
	var normalString:String = "Normal string"
	var safeString:String? = "Safe string"
	println(normalString)
	println(safeString)
							
					

The decompiled code looks like this

						
					
	public final class TypesKt { 
		public static final void main(String[] arg) {
		 //...
	     String normalString = "Normal string";
	     String safeString = "Safe string";
	     System.out.println(normalString);
	     System.out.println(safeString);
	   }
	}
							
						

Since the Kotlin compiler performs the null checks, the decompiled code looks very similar to a regular Java piece.

In the next part we'll take a look at accessing methods in a safe way and get introduced to couple of other operators.