Optionality

Optionality

Intro

Optional values which can be null or have a value. Determined at runtime or compile time

Code

fun myFunction(name: String? = null) {
    val displayName = name ?: "defaultName"
    println("Name: $displayName")
}

fun main() {
    myFunction() // Output: Name: defaultName
    myFunction("Bob") // Output: Name: Bob
    myFunction(null) // Output: Name: defaultName
}

Check optionality

Do if true || not null

fun processNullableString(text: String?) {
    // Safe call operator: executes the lambda only if 'text' is not null
    text?.let {
        println("The text is: $it")
    }

if else

if else statement?

fun processNullableString(text: String?) {
    if (text != null) {
        // 'text' is not null, safe to use it directly
        println("The text is: $text")
        // Perform operations on 'text'
    } else {
        // 'text' is null
        println("The text is null")
        // Handle the case where 'text' is null
    }
}

if let

If let equivalent in kotlin ?. let { } ?: run { }
swift counterpart

fun process(text: String?) {
    text?.let {
        // Code to execute if text is not null
        println("Text is not null: $it")
    } ?: run {
        // Code to execute if text is null (else block)
        println("Text is null")
    }
}

Default value

var name: String? = null
val defaultName = name ?: "Sensehack"
println(defaultName)

name = "Kay"
val assignedName = name ?: "Kautilya"

println(assignedName)

Mind Map

Swift counterpart Optionals

If let optional

One option is to use a safe cast operator + safe call + let:

(getUser() as? User)?.let { user ->
    ...
}

Another would be to use a smart cast inside the lambda passed to let:

getUser().let { user ->
    if (user is User) {
        ...
    }
}

But maybe the most readable would be to just introduce a variable and use a smart cast right there:

val user = getUser()
if (user is User) {
    ...
}

Reference | SO post

also

In Kotlin, also is a scope function that operates on an object and returns the object itself after executing a block of code. It's useful for performing side effects or additional operations on an object without modifying it or interrupting method chaining. The object is referenced within the also block using it (by default) or a custom name if specified.

fun main() {
    val numbers = mutableListOf(1, 2, 3)
    val result = numbers.also {
        println("Original list: $it") // Prints: Original list: [1, 2, 3]
        it.add(4)
    }
    println("Modified list: $result") // Prints: Modified list: [1, 2, 3, 4]
}

swift guard

guard let e = email.text , !e.isEmpty else { return }

guard

val e = email.text?.let { it } ?: return

if let

swift equivalent

val a = b?.let {  
    // If b is not null.  
} ?: run {  
    // If b is null.  
}

let

In Kotlin, the let function's return type defaults to Unit if the lambda expression within it does not explicitly return a value. Unit is Kotlin's equivalent of void in Java, signifying that a function does not return a meaningful value.

When a let block's last expression is a statement that doesn't produce a value (like a variable assignment or a for loop without a return), the let function implicitly returns Unit. However, if the lambda contains an expression that yields a value, that value becomes the return value of the let function.

suspend fun openInBrowser(url: String): Pair<Boolean, LoginData?>  {
val loginData = callbackData?.let {  
    println("Successful callback!")  
    it  
} ?: run {  
    println("Failure in authenticating with user credentials")  
    return Pair(false, null)  
}
}