Hopping Islands: From Java to Kotlin Part 4

This series is aimed at existing Java developers that might feel tempted to switch over.
The goal of this series is to introduce Kotlin as a language you can use in tandem with Java, or even as a complete replacement.
Across the series, I will be covering a multitude of topics (usually with a few topics per part) on the benefits of using Kotlin over Java.
Here are the topics I have picked out for part 4:
  • Generics
  • Contracts
  • Inline Classes

Generics

What are generics, you might ask?
Generics are a compiler feature that give an easy way to provide functions that are applicable to multiple types of objects within user given bounds without any extra cost at runtime
Basically, everything except for primitive number types (byte char short int long float and double) is an Object.
But the compiler (and IDE) can analyze your code to see if it meets certain criteria, and it allows you to do extra stuff with that information.


Say I wanted to make a function in Java that only takes a List of things that are a subclass of type Dog and make every Dog in the List<Dog> Bark.
First, here's Dog
Code:
public abstract class Dog {

    final String dogBreed;
    final String barkSound;

    Dog(String dogBreed, String barkSound) {
        this.dogBreed = dogBreed;
        this.barkSound = barkSound;
    }

    void bark()
}
Here's how you would define a function that makes all subspecies of the Dog species T in a List bark.
Code:
public static <T extends Dog> void barkDogs(List<T> dogList) {
    dogList.forEach(T::bark);
}
This will bark all the sub species of in the list.
You will notice the <T extends Dog> in the function definition.
The T is just the name you are giving to that generic type in that function.
You can use any (valid identifier) name you want to, even cAt.
The <T extends Dog> tells the compiler to make sure that any time T is used, it is actually a subclass of Dog.
Thats how you know that T has the bark function, is because it is a species of .
Okay, if you didn't really understand generics, you should get the gist of it.
As a small note, you cannot access the generic type information at runtime, as everything is actually an Object!
Now, on to kotlin's generics!


Well, for the most part they are the same.
Here's what the dogs would look like in Kotlin!
Code:
abstract class Dog(val dogBreed: String, val barkSound: String) {
    fun bark() = println("$dogBreed says: $barkSound! Good dog!")
}
Now here's what the function in kotlin would look like as an extension function:

Code:
fun <T: Dog> List<T>.barkAllDogs() = forEach(T::bark)
Not too remarkable, eh?
Hold your horses, Kotlin has an extra level to generics.
With generics in Java, all type information is erased at runtime.
This means that you dont really know what anything actually is, and the compiler cannot guarantee that some casts will work.

Kotlin has a solution. Reified generics.
Reified generics open some possibilities previously not possible in Java, such as the compiler guaranteeing type information is available inside a function.
The caveat to this is that if you want to reify a generic type, you MUST inline the function and you MUST say so.
Here is an example case of where you can not use regular generics and must use reified generics.
Code:
fun <T> List<T>.filterToArray(predicate: (T) -> Boolean) =
    with(filter(predicate)) { // Now in context of the filtered list
        Array<T>(this.size, ::get) // Cannot use 'T' as reified type parameter. Use a class instead.
    }
Weird, looks like it should work. Add 2 words, and it will!
Code:
inline fun <reified T> List<T>.filterToArray(predicate: (T) -> Boolean) =
    with(filter(predicate)) { // Now in context of the filtered list
        Array<T>(this.size, ::get) // Ding ding!
    }
This can be used for other things as well, such as getting the type of something put in to the function.
Your imagination (and the feature set of the JVM) is the only limiting factor!
Contracts

Contracts in kotlin are a way for you to programatically tell the compiler what you say is going to happen.
It will take your word for it, despite what you actually do with the information you are putting under contract!
Here's an example of where contracts are be useful. Say I want to create a function that takes a lambda, a lambda which I know will only run once.
I know it will only run once, so I should be able to initialize a val
that was declared outside of the lambda, right?
Well, let's try it out.
Code:
fun doThingOnce(lambda: () -> Unit) = lambda()

fun main() {
    val name: String
    doThingOnce { name = "My name" }
}
Eek, it gives us an error: Captured values initialization is forbidden due to possible reassignment.
That's unfair. The standard library has functions like run that can do what I want my function to do!
Well, good news. You can too! Contracts to the rescue!
Contracts are quite basic for now, but they do allow for some good functionality.
There are some rules to contracts:
  • The first line of a function with a contract must be the contract
  • Actually there's just 1 concrete rule, I just like lists.

So here's what a contract looks like
Code:
contract {
    callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
This is the definition of a contract that claims blockwill run exactly once.
Okay, so let's put that at the beginning of our function and see what happens.
NOTE: AS OF THIS POST, CONTRACTS ARE EXPERIMENTAL IN KOTLIN AND YOU MUST EXPLICITLY ENABLE THEM BEFORE THEY WORK!
Code:
fun doThingOnce(lambda: () -> Unit) {
    contract {
        callsInPlace(lambda, InvocationKind.EXACTLY_ONCE)
    }
    lambda()
}

fun main() {
    var name: String
    doThingOnce { name = "My name" }
}
No error! And it works! But what if I run it twice... Hehehehe
Well, it will run twice. But you shouldn't abuse contracts for reasons that should be obvious if other people are going to read your code.
Inline classes

NOTE: AS OF THIS POST, INLINE CLASSES ARE EXPERIMENTAL IN KOTLIN AND YOU MUST EXPLICITLY ENABLE THEM BEFORE THEY WORK!
Inline classes are a really neat feature in Kotlin.
Normally, only primitive classes get optimized heavily during runtime, but wrapper classes like Java's Integer don't get the same special treatment despite having nearly identical usage as it's primitive brother.
Inline classes allow you to bypass this boxing problem in some cases.
However, inline classes have a few restrictions:
  • An inline class cannot have an init block
  • An inline class can only have 1 primary constructor parameter, and it must be a val
  • Inline classes CAN have properties, but CANNOT have backing fields
  • As such, Inline classes CANNOT have late initialized or delegated properties (coming soon to a HIFJTK near you)

Now, how do you create an inline class? It's a mystical art they don't teach you in Java school.
Code:
inline class InlineClassName(val underlyingValue: ClassType)
Extreme stuff, I'm not sure if you're ready... But, if you're confident enough to write that, let's keep trudging on!
Now, here are the benefits of inline classes:
  • They CAN inherit from interfaces
  • They CAN be used where the inherited interfaces are used
  • They get optimized as the underlying type ONLY WHEN USED AS THE UNDERLYING TYPE

This allows you to get a performance uplift when using them in the underlying type use case
Example: Inline classes are currently being used in the standard library to implement unsigned primitives in Kotlin!
Another example, this time a bit more visual:
Code:
interface Colors {
    val value: Int
    val alpha: Int
        get() = (value shr 24) and 0xFF
    val red: Int
        get() = (value shr 16) and 0xFF
    val green: Int
        get() = (value shr 8) and 0xFF
    val blue: Int
        get() = value and 0xFF

}

inline class ARGB(override val value: Int): Colors {
    override fun toString(): String = "ARGB()"
}

// Used as Colors, not optimized as Int
fun printColors(colors: Colors) = with(colors) {
    println("[$alpha, $red, $green, $blue]")
}

// Used as ARGB, optimized as Int. At runtime, this essentially becomes a function that takes an Int. Weird, right?
fun printArgb(argb: ARGB) = println(argb)

// Used as ARGB?, NOT optimized as Int, as it is essentially Int? (java Integer) at runtime.
fun argbIsNull(argb: ARGB?) = argb == null

// Used as T, NOT optimized as Int.
fun <T> genericFunction(genericValue: T) = println(genericValue)

fun main() {
    val colorsRaw = ARGB(0x04143C09)
    printColors(colorsRaw)
    printArgb(colorsRaw)
    print(argbIsNull(colorsRaw))
    print(genericFunction(colorsRaw))
}
That's all for this post. Hope you learned something and are more inclined to start using Kotlin!
The menu for part 5:
  • open class
  • lateinit
  • delegates