Study Guide 2023+

kotlin

Warning: These notes are partial, ongoing, incomplete, and may contain typos/inaccuracies. (They are kept factually accurate, time permitting.)

They are being united from many disparate notes created in the past and the layout/organization will gradually improve with time!

Please view them on a computer as they are not optimized for mobile (although you can still view them on Mobile along with the Flashcards at your own risk)!

Topics and code examples are lazy-loaded and may require two-clicks from the TOC to correctly calculate the updated x,y coordinates (after rendering). Thanks!

Kotlin: General Concepts

Improvements

Kotlin was introduced as a Java ecosystem language variant with the following improvements:

  1. More concise (less verbose) syntax:
    • function to fun.
    • unit return Type for void Methods.
    • : replaces both extends and implements.
    • new Constructor keyword isn't required.
  2. Greater Null Safety and Safe Navigation support:
    • Elvis operator.
    • ? Nullable Type suffix.
    • null and Nothing Type.
    • Nullable disallowed by default.
  3. Functional programming paradigm oriented from the beginning:
    • Functions can be free-standing and don't have to be attached to or declared within a Class.
    • Functions don't have to be Methods.
    • Tail Recursion optimization.
  4. Many performance improvements:
    • Asynchronous light-weight Coroutines pre-Java 21.
    • Type inferencing.
    • Compilation.
    • Singleton declaration.
  5. Greater flexibility with Class and Variable declarations:
    • val (constant, replaces final, immutable) and var (mutable).
    • Constructors in Class definition.
    • public visibility by default.
    • static keyword removed.
    • open must be explicitly set in Concrete Class definitions to allow Subclassing.
    • Keyword support for companion object and object Singletons.
    • lateinit lazy Variable initialization.
  1. https://shirsh94.medium.com/top-100-kotlin-interview-questions-and-answers-d1f6785f336a

Code samples:

  1. https://github.com/Thoughtscript/kotlin_2024/blob/main/kotlin/src/main/kotlin/io/thoughtscript/example/language/Function.kt

Kotlin: Classes and Types

Types Equality

Unlike Java, Kotlin equality checks mirror JavaScript supporting both "looser" and "stricter" degrees of comparison:

  1. == (Structural equality) compares by Values.
  2. === (Referential equality) compares by same Pointer/Memory Address.
  3. null has Nothing Type.

Consult https://kotlinlang.org/docs/equality.html

Classes

  1. Constructors are parameterized on Class definitions. (Similar to GoLang struct.)
  2. Classes aren't subclassable (final) by default: use open to override (Interfaces and Abstract Classes are).
  3. implements and extends are both replaced by :.
  4. Interfaces have some features that Abstract Classes do in Java (can define some Getters/Setters). Otherwise, Interfaces define Method signatures (Abstract Methods) and can't be initialized (Abstract Classes can define state and have initialized fields) like usual.
  5. public is the default visibility.
// By default all Classes can't be inherited from.
// Add the open keyword to allow that.

// Note the constructor in parentheticals
open class ExampleA(a: String, b: String) {
    var stringVariable: String = a
    val stringValue: String = b

    // Method - Function on Class
    fun testA(): Unit {
        println("stringVariable: $stringVariable, stringValue: $stringValue")
    }
}

class ExampleB(a: String, b: String, c: String): ExampleA(a, b) {
    var additionalStringVariable: String = c

    fun testB(): Unit {
        println("stringVariable: $stringVariable, stringValue: $stringValue, additionalStringVariable: $additionalStringVariable")
    }

    // Inner class
    inner class ExampleC(d: String) {
        val additionalStringValue: String = d
        fun testC(): Unit {
            println("stringVariable: $stringVariable, stringValue: $stringValue, additionalStringVariable: $additionalStringVariable, additionalStringValue: $additionalStringValue")
        }
    }
}

open class ImplicitGettersAndSetters() {
    var stringVariable: String = ""
    val stringValue: String = "I'm set already as a val"

    // Method - Function on Class
    fun getFields(): Unit {
        println("stringVariable: $stringVariable, stringValue: $stringValue")
    }
}
  1. https://kotlinlang.org/docs/equality.html

Code samples:

  1. https://github.com/Thoughtscript/kotlin_2024/blob/main/kotlin/src/main/kotlin/io/thoughtscript/example/language/Classes.kt
  2. https://github.com/Thoughtscript/kotlin_2024/blob/main/kotlin/src/main/kotlin/io/thoughtscript/example/language/AbstractClass.kt
  3. https://github.com/Thoughtscript/kotlin_2024/blob/main/kotlin/src/main/kotlin/io/thoughtscript/example/language/Interfaces.kt

Kotlin: Variables

Variable Declaration

  1. val specifies an immutable Variable (constant, rather than final).
  2. var specifies a mutable Variable.

Destructing

Kotlin supports Destructuring the fields of an Object into separate Variables:

val (name, age) = person

Lazy Initialization

lateinit allows Variables to be initialized lazily. They must be initialized before they're used:

fun exampleA(): Unit {
    // Can't be val
    lateinit var name: String  // Can't be initialized
    name = "I'm initialized" // Placeholder for lengthy or asynchronous assignment
    println("I'm initialized with $name")
}

Classes support Receivers, ::, and the .isInitialized field:

class Example() {
    lateinit var name: String  // Can't be initialized

    // Method - Function on Class
    fun isInitializedExample(): Unit {
        name = "I'm initialized" // Placeholder for lengthy or asynchronous assignment

        // Supports :: and .isInitialized in Classes
        if (::name.isInitialized) {
            println("Initialized value present: $name")

        } else {
            println("var name is not initialized yet")

        }
    }
}
  1. https://kotlinlang.org/docs/properties.html#late-initialized-properties-and-variables
  2. https://www.baeldung.com/kotlin/checking-lateinit

Kotlin: Null Safety

Kotlin supports advanced Null Safety features.

Nullable

By default, Types aren't Nullable unless they're explicitly declared so with a suffixed ?:

// From the Official Documentation
var a: String = "abc" // Regular initialization means non-nullable by default
a = null // compilation error
// From the Official Documentation
var b: String? = "abc" // can be set to null
b = null // ok

Read more here: https://kotlinlang.org/docs/null-safety.html#checking-for-null-in-conditions

Elvis Operator

Kotlin supports the Ruby/Rails Type Safety Navigation:

  1. Elvis operator ? (akin to Ruby/Rails).
  2. .let() (handles non-null), .run() handles null
fun chainedSafeElvis(arg: Any?): Unit {

  // if null then execute block
  arg?.let {
     // if not-null then execute this block
     // with reference to obj via 'it'
     println("chainedSafeElvis: $it")

  } ?:run {
     println("chainedSafeElvis: Null found")
  }
}
  1. https://kotlinlang.org/docs/null-safety.html#checking-for-null-in-conditions

Code samples:

  1. https://github.com/Thoughtscript/kotlin_2024/blob/main/kotlin/src/main/kotlin/io/thoughtscript/example/language/SafeNavigation.kt

Kotlin: Coroutines

Kotlin supports Asynchronous operations and light-weight Threading.

Suspend Functions

suspend indicates that a Function can be used in either Asynchronous or blocking operations.

They can be called, paused, or stopped.

// function to be launched
// suspend indicates that the Function can be called in async operations, paused, or stopped
suspend fun suspendedFunctionExampleA(text: String): String {
    println("I'm in the returned suspended function with $text")
    return "I'm done: $text"
}

suspend fun suspendedFunctionExampleB(text: String) = coroutineScope {
    println("I'm in the suspended function with no return: $text")
    // No return
}

Coroutines

Coroutines, suspend functions, etc. provided support for lightweight virtual threading.

// https://kotlinlang.org/docs/coroutines-overview.html
// Coroutines are Kotlin's approach to Threading and Asynchronous operations
// Akin to Java's Lightweight Virtual Threads

// See also Scope builder notation: https://kotlinlang.org/docs/coroutines-basics.html#scope-builder
fun spawnExecExample() = runBlocking {

    println("I'm in the blocking scope")

    // Define a Channel like in go
    val channel = Channel<String>()

    // Declare a coroutine block (like a go routine)
    // Spawns a light-weight virtual thread
    // is a Job

    // Use GlobalScope.launch now
    GlobalScope.launch {
        println("I'm in a coroutine")

        // https://kotlinlang.org/docs/composing-suspending-functions.html#concurrent-using-async
        // Conceptually very similar to Launch except it's deferred and can use .await()
        val resultA = async { suspendedFunctionExampleA("exampleA") }.await()
        println("I'm awaited at resultA: $resultA")

        // Concurrent launching - not blocking!
        val resultB = async { suspendedFunctionExampleA("exampleB") }.await()
        val resultC = async { suspendedFunctionExampleA("exampleC") }.await()
        // The documention shows an example where async operations are composed
        // but using the .await() is required to print a returned a value like in the below

        async { suspendedFunctionExampleB("exampleD") }

        // IPC send to channel
        async {
            for (x in 1..10) channel.send("$x")
            channel.close() // close channel
        }

        // Can compose the above without using promises
        println("I'm composed: $resultA, $resultB, $resultC")
    }

    for (y in channel) println("Channel received: $y")
    // Commenting out this line will prevent the blocking scope from printing everything!!
}

https://github.com/Thoughtscript/kotlin_2024/blob/main/kotlin/src/main/kotlin/io/thoughtscript/example/language/Asynchronous.kt

Apparently, these are still more performant than (Java 21) Virtual Threads: https://medium.com/@AliBehzadian/java-virtual-threads-performance-vs-kotlin-coroutines-f6b1bf798b16

  1. https://medium.com/@AliBehzadian/java-virtual-threads-performance-vs-kotlin-coroutines-f6b1bf798b16

Code samples:

  1. https://github.com/Thoughtscript/kotlin_2024/blob/main/kotlin/src/main/kotlin/io/thoughtscript/example/language/Asynchronous.kt

Kotlin: Handling Static Methods and Singletons

Static Keyword

  1. No static Keyword.
    • init block instead of static blocks for complex initializations.
  2. companion object can be used to define the equivalent of static Methods.

Singletons

Singletons can be declared through a single keyword: object:

object Singleton {
    fun doSomething() = "Doing something"
}

Consult: https://www.baeldung.com/kotlin/singleton-classes

Companion Objects

  1. companion object can be used to define the equivalent of static Methods.
  2. Only one companion instance is present at any given time (object) and allows methods to be called without declaring a new instance of the Class.
class ReadRow {
    companion object {
        @JvmStatic
        fun execute(conn: Connection) {
            val query = "SELECT * FROM ..."
        }
    }
}
  1. https://kotlinlang.org/docs/classes.html#companion-objects
  2. https://www.baeldung.com/kotlin/singleton-classes

Code samples:

  1. https://github.com/Thoughtscript/cockroachdb-kotlin-client/blob/master/cockroachdb-kotlin-client/src/main/kotlin/com/cockroachlabs/client/queries/ReadRow.kt