Swift 'if let' statement equivalent in Kotlin

Kotlin

Kotlin Problem Overview


In Kotlin is there an equivalent to the Swift code below?

if let a = b.val {

} else {

}

Kotlin Solutions


Solution 1 - Kotlin

You can use the let-function like this:

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

Note that you need to call the run function only if you need a block of code. You can remove the run-block if you only have a oneliner after the elvis-operator (?:).

Be aware that the run block will be evaluated either if b is null, or if the let-block evaluates to null.

Because of this, you usually want just an if expression.

val a = if (b == null) {
    // ...
} else {
    // ...
}

In this case, the else-block will only be evaluated if b is not null.

Solution 2 - Kotlin

Let's first ensure we understand the semantics of the provided Swift idiom:

if let a = <expr> {
     // then-block
}
else {
     // else-block
}

It means this: "if the <expr> results in a non-nil optional, enter the then-block with the symbol a bound to the unwrapped value. Otherwise enter the else block.

Especially note that a is bound only within the then-block. In Kotlin you can easily get this by calling

<expr>?.also { a ->
    // then-block
}

and you can add an else-block like this:

<expr>?.also { a ->
    // then-block
} ?: run {
    // else-block
}

This results in the same semantics as the Swift idiom.

Solution 3 - Kotlin

My answer is totally a copy cat from the others. However, I cannot understand their expression easily. So I guess it would be nice to provide an more understandable answer.

In swift:

if let a = b.val {
  //use "a" as unwrapped
}
else {

}

In Kotlin:

b.val?.let{a -> 
  //use "a" as unwrapped
} ?: run{
  //else case
}

Solution 4 - Kotlin

if let statement.

Swift's Optional Binding (so called if-let statement) is used to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. So, an Optional Binding for the if-let statement is as follows:

>Swift's if-let statement:

let b: Int? = 50

if let a: Int = b {
    print("Good news!")
} else {
    print("Equal to 'nil' or not set")
}

/*  RESULT: Good news!  */

In Kotlin, like in Swift, to avoid crashes caused by trying to access a null value when it’s not expected, a specific syntax (like b.let { } in second example) is provided for properly unwrapping nullable types:

>Kotlin equivalent 1 of Swift's if-let statement:

val b: Int? = null
val a = b

if (a != null) { 
    println("Good news!")
} else { 
    println("Equal to 'null' or not set")
}

/*  RESULT: Equal to 'null' or not set  */

Kotlin’s let function, when used in combination with the safe-call operator ?:, provides a concise way to handle nullable expressions.

>Kotlin equivalent 2 (Inline let function and Elvis Operator) of Swift's if-let statement:

val b: Int? = null

val a = b.let { nonNullable -> nonNullable } ?: "Equal to 'null' or not set"
println(a)

/*  RESULT: Equal to 'null' or not set  */



guard let statement.

guard-let statement in Swift is simple and powerful. It checks for some condition and if it evaluates to be false, then the else statement executes which normally will exit a method.

>Let's explore a Swift's guard-let statement:

let b: Int? = nil

func method() {
    guard let a: Int = b else {
        print("Equal to 'nil' or not set")
        return
    }
    print("Good news!")
}
method()

/*  RESULT: Equal to 'nil' or not set  */

>Kotlin's similar effect of Swift's guard-let statement:

Unlike Swift, in Kotlin, there is no guard statement at all. However, you can use the Elvis Operator?: for getting a similar effect.

val b: Int? = 50

fun method() {
    val a = b ?: return println("Equal to 'null' or not set")
    return println("Good news!")
}
method()

/*  RESULT: Good news!  */

Solution 5 - Kotlin

there are two answers above, both got a lot acceptances:

  1. str?.let{ } ?: run { }
  2. str?.also{ } ?: run { }

Both seem to work in most of the usages, but #1 would fail in the following test:

enter image description here

#2 seems better.

Solution 6 - Kotlin

Unlike Swift, Its not necessary to unwrap the optional before using it in Kotlin. We could just check if the value is non null and the compiler tracks the information about the check you performed and allows to use it as unwrapped.

In Swift:

if let a = b.val {
  //use "a" as unwrapped
} else {

}

In Kotlin:

if b.val != null {
  //use "b.val" as unwrapped
} else {

}

Refer Documentation: (null-safety) for more such use cases

Solution 7 - Kotlin

Here's how to only execute code when name is not null:

var name: String? = null
name?.let { nameUnwrapp ->
    println(nameUnwrapp)  // not printed because name was null
}
name = "Alex"
name?.let { nameUnwrapp ->
    println(nameUnwrapp)  // printed "Alex"
}

Solution 8 - Kotlin

Here's my variant, limited to the very common "if not null" case.

First of all, define this somewhere:

inline fun <T> ifNotNull(obj: T?, block: (T) -> Unit) {
    if (obj != null) {
        block(obj)
    }
}

It should probably be internal, to avoid conflicts.

Now, convert this Swift code:

if let item = obj.item {
    doSomething(item)
}

To this Kotlin code:

ifNotNull(obj.item) { item -> 
    doSomething(item)
}

Note that as always with blocks in Kotlin, you can drop the argument and use it:

ifNotNull(obj.item) {
    doSomething(it)
}

But if the block is more than 1-2 lines, it's probably best to be explicit.

This is as similar to Swift as I could find.

Solution 9 - Kotlin

There is a similar way in kotlin to achieve Swift's style if-let

if (val a = b) {
    a.doFirst()
    a.doSecond()
}

You can also assigned multiple nullable values

if (val name = nullableName, val age = nullableAge) {
    doSomething(name, age)
}

This kind of approach will be more suitable if the nullable values is used for more than 1 times. In my opinion, it helps from the performance aspect because the nullable value will be checked only once.

source: Kotlin Discussion

Solution 10 - Kotlin

I'm adding this answer to clarify the accepted answer because it's too big for a comment.

The general pattern here is that you can use any combination of the Scope Functions available in Kotlin separated by the Elvis Operator like this:

<nullable>?.<scope function> {
    // code if not null
} :? <scope function> {
    // code if null
}

For example:

val gradedStudent = student?.apply {
    grade = newGrade
} :? with(newGrade) {
    Student().apply { grade = newGrade }
}

Solution 11 - Kotlin

The cleanest option in my opinion is this

Swift:

if let a = b.val {

} else {

}

Kotlin

b.val.also { a ->
           
} ?: run {

}

Solution 12 - Kotlin

> Swift if let statement in Kotlin

The short answer is use simple IF-ELSE as by the time of this comment there is no equivalent in Kotlin LET,

    if(A.isNull()){
// A is null
    }else{
// A is not null
    }

Solution 13 - Kotlin

we can get the same Unwraping syntax like Swift if let using inline fun

inline fun <T:Any?> T?.unwrap(callback: (T)-> Unit) : Boolean {
    return if (this != null) {
        this?.let(callback)
        true
    }else {
        false
    }
}

Uses: :

        val  name : String? = null
        val  rollNo : String? = ""
        var namesList: ArrayList<String>?  = null

        if (name.unwrap { name ->

                Log.i("Dhiru", "Name have value on it  $name")

            })else if ( rollNo.unwrap {
                Log.i("Dhiru","Roll have value on it")

            }) else if (namesList.unwrap {  namesList  ->
                Log.i("Dhiru","This is Called when names list have value ")
            })  {
             Log.i("Dhiru","No Field have value on it ")
        }

Solution 14 - Kotlin

The problem with the Any?.let {} ?: run {} constructions is that:

  • It only allows for one non-null check per statement
  • If the let block returns null the run block is evaluated anyway
  • It's not possible to perform multiple checks in a switch/when style

A solution which tackles most of these problems is to define functions like the following:

private inline fun <A> ifNotNull(p1: A?, block: (A) -> Unit): Unit? {
    if (p1 != null) {
        return block.invoke(p1)
    }
    return null
}

private inline fun <A, B> ifNotNull(p1: A?, p2: B?, block: (A, B) -> Unit): Unit? {
    if (p1 != null && p2 != null) {
        return block.invoke(p1, p2)
    }
    return null
}

private inline fun <A, B, C> ifNotNull(p1: A?, p2: B?, p3: C?, block: (A, B, C) -> Unit): Unit? {
    if (p1 != null && p2 != null && p3 != null) {
        return block.invoke(p1, p2, p3)
    }
    return null
}

This would allow for a statement like:

ifNotNull(a, b) { a, b ->
    // code when a, b are not null
} ?:
ifNotNull(c) { c ->
    // code when a, b are null and c not null
} ?: 
ifNotNull(d, e, f) { d, e, f ->
    // code when a, b, c are null and d, e, f not null
} ?: run {
    // code which should be performed if a, b, c, d, e and f are null
}

The only caveat is that continue and break statements are not supported if executed within a loop compared to Swift's if let equivalent.

Solution 15 - Kotlin

If b is a member variable then this approach seems most readable to me:

val b = this.b
if (b == null) {
    return
}
println("non nullable : ${b}")

This is also consistent with how it works in swift, where a new local variable shadows the member variable.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questioniadcialim24View Question on Stackoverflow
Solution 1 - KotlinmarstranView Answer on Stackoverflow
Solution 2 - KotlinMarko TopolnikView Answer on Stackoverflow
Solution 3 - KotlinWu Yuan ChunView Answer on Stackoverflow
Solution 4 - KotlinAndy JazzView Answer on Stackoverflow
Solution 5 - KotlinSeanView Answer on Stackoverflow
Solution 6 - KotlinShahzin KSView Answer on Stackoverflow
Solution 7 - KotlinАлександр ЯковенкоView Answer on Stackoverflow
Solution 8 - KotlinnoamtmView Answer on Stackoverflow
Solution 9 - KotlinRichardView Answer on Stackoverflow
Solution 10 - KotlinSir CodesalotView Answer on Stackoverflow
Solution 11 - KotlinStiivView Answer on Stackoverflow
Solution 12 - Kotlinbastami82View Answer on Stackoverflow
Solution 13 - KotlinDhiruView Answer on Stackoverflow
Solution 14 - KotlinWerner AltewischerView Answer on Stackoverflow
Solution 15 - KotlinSteve VermeulenView Answer on Stackoverflow