menu

Intro to Kotlin

A statically-typed programming language, that runs on the Java virtual machine

Official Reference • IntelliJ


Note that this is a showcase of Kotlin's powerful features over Java that you might not encounter on first use. For full details, I strongly recommend devs read the entire reference linked above. It's worth it.
Extension Functions
Official Reference
My motherload of extension functions for Android
In Java, we often require new methods for existing classes. Rather than extending the class, we may create static methods that take in the object reference and modify it accordingly.
Test test; //assume implementation

static void update(Test test);
The call involves placing the method before the reference, which may be harder to read when chained
show(update(clear(init(test)))); 
Kotlin on the other hand, allows for extension functions. Given a type, it can add a method onto it, as if it were in the original class. The implementation is done statically, but it produces a very elegant outcome:
fun Test.init() //assume implementation
fun Test.clear()
...
val test: Test //assume implementation
test.init().clear().update().show()
Extensions are especially powerful as they can be used on null types; it allows for methods such as
list.getFirstOrNull()
Builder Pattern
Android library example
Java builder patterns are very common, to allow for updating variables one at a time
class Builder {
    int a;
    int b;
    String c;

    Builder setA(int a) {
        this.a = a;
        return this;
    }

    Builder setB(int b) {
        this.b = b;
        return this;
    }

    Builder setC(String c) {
        this.c = c;
        return this;
    }
}

static Builder buildExample() {
    Builder builder = new Builder();
    int i = 0;
    builder.setA(i);
    i+=5;
    return builder.setB(i).setC("Done");
}
Kotlin not only does not require a separate builder class, but allows you to use lambda functions to directly modify the builder
class Builder(var a: Int, var b: Int, var c: String)

fun build(builder: Builder.() -> Unit): Builder
    = with(Builder()) { builder() }

fun exampleBuild() = build {
    val i = 0
    a = i
    i += 5
    b = i
    c = "Done"
}
This example showcases several things
  • Classes with a primary constructor can directly add it in the header. No need for a this.a = a pattern
  • Functions like build with a terminating lambda argument can directly use braces to add the function. This allows for syntax similar to that of gradle
  • All classes have a with function, which gives direct access to the object in question, returning it in the end. There is also apply which returns the last value in the function
  • Functions with one action can use '=' without the need for braces. The return type is also inferred
Objects
Official Reference
Want a singleton? Use an object. It's that simple. Kotlin by default does not have static implementations, though they may be added through the @JvmStatic annotation. The benefits of singletons are clear, as they adhere to object oriented practices and are actually extensible.
Operator Overloading
Official Reference
Matrix example in Kotlin
If we had a matrix class, wouldn't it be awesome if we could use operators to execute matrixA + matrixB? You can do that in Kotlin. Simply do
operator fun plus(addend: Matrix) = add(addend)
//add is our function inside Matrix
We may also override get and invoke to add our own () and [] calls
Default Values
Like python, Kotlin supports default values
data class Test(val a: Int = 0, val b: String = "POTATO")

val test = Test(b = "HI")
This also showcases data classes, which are made for POJOs. They auto implement hashCode(), equals(), and toString() to reflect their internal variables and have a copy method
Getters and Setters
Official Reference
Unlike Java, Kotlin upholds property style syntax. There is no need to create your own getters and setters, as they are done for you. By default, they do nothing more than retrieve the field, or save the new value into the field. You may override it by doing the following:
val opposite: Boolean //returns the opposite of what is saved
	//field is the name of the stored value (backing field)
	//get is not overridden
	set(value) {
		field = !value
	}
Delegates
Official Reference
Lazy Resettable Delegate
Delegation is a very powerful structure that allows us to allow other classes to handle our methods or variables. This allows for lazy patterns (where an execution is only done upon first get), and allowing some basic form of multiple extensions, by delegating interface methods to fully implemented classes.