# Why DOESN’T Kotlin smart cast work, even when both are \`val\`s

**URL:** <https://discuss.kotlinlang.org/t/why-doesn-t-kotlin-smart-cast-work-even-when-both-are-val-s/17333>\
**Category:** Language Design\
**Created:** [April 25, 2020, 1:55pm UTC](https://discuss.kotlinlang.org/t/why-doesn-t-kotlin-smart-cast-work-even-when-both-are-val-s/17333 "2020-04-25T13:55:20Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![gopalakshintala](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gopalakshintala/32/6676_2.png) [@gopalakshintala](https://discuss.kotlinlang.org/u/gopalakshintala)\
**Post date:** [April 25, 2020, 1:55pm UTC](https://discuss.kotlinlang.org/t/why-doesn-t-kotlin-smart-cast-work-even-when-both-are-val-s/17333/1 "2020-04-25T13:55:20Z")

</div>

In the below code, both the variables are `val` s, but the smart cast doesn’t work even after the null check. Why?

```auto
fun SLLNode?.sumListWith(node: SLLNode?, carry: Int = 0): SLLNode? =
    when {
        this == null && node == null -> if (carry == 0) null else SLLNode(carry)
        this == null -> node.also { it!!.value += carry } // Smart cast doesn't work here.
        node == null -> this.also { value += carry } // Works here.
        else -> {
            ...
        }
    }

```

---

<div class="post-metadata">

**Author:** ![seekdasky](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/seekdasky/32/4673_2.png) [@seekdasky](https://discuss.kotlinlang.org/u/seekdasky)\
**Post date:** [April 25, 2020, 4:56pm UTC](https://discuss.kotlinlang.org/t/why-doesn-t-kotlin-smart-cast-work-even-when-both-are-val-s/17333/2 "2020-04-25T16:56:57Z")

</div>

If we look at the first condition, you can see it can fail either because `this` is not null or because `node` is not null, if this condition fails we don’t have any information about whether `node` is not null, as far as the compiler can tell, the condition could have failed because of `this != null`,

so when the compiler infer the type of `node` in the second condition, it just doesn’t know if `node` is not null.

Your code is right tho, `node` can not be null in the second condition, but it seems the compiler is not able to determine that. it probably isn’t able to “link” the first and second condition to infer that `node` is in fact not null.

if you want smart cast just check that `node` is not null in your second condition, maybe type inference will be enhanced enough in the 1.4 release to cover that kind of use case.

EDIT: I tried this code in the Kotlin playground with 1.4 M1 and the smart cast is not made 😕

---

<div class="post-metadata">

**Author:** ![nickallendev](https://avatars.discourse-cdn.com/v4/letter/n/cdc98d/32.png) [@nickallendev](https://discuss.kotlinlang.org/u/nickallendev)\
**Post date:** [April 25, 2020, 5:16pm UTC](https://discuss.kotlinlang.org/t/why-doesn-t-kotlin-smart-cast-work-even-when-both-are-val-s/17333/3 "2020-04-25T17:16:34Z")

</div>

The list of cases that allow smart casts are here: [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts)

It really just looks at simple direct checks and inverse checks that can alone direct control flow. It doesn’t do any “is it possible?” analysis or logic simplification.

---

<div class="post-metadata">

**Author:** ![dalewking](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/dalewking/32/1496_2.png) [@dalewking](https://discuss.kotlinlang.org/u/dalewking)\
**Post date:** [April 12, 2021, 2:13pm UTC](https://discuss.kotlinlang.org/t/why-doesn-t-kotlin-smart-cast-work-even-when-both-are-val-s/17333/4 "2021-04-12T14:13:09Z")

</div>

> [@gopalakshintala](#):
>
> In the below code, both the variables are `val` s, but the smart cast doesn’t work even after the null check. Why?
> 
> ```auto
> fun SLLNode?.sumListWith(node: SLLNode?, carry: Int = 0): SLLNode? =
> when {
> this == null && node == null -> if (carry == 0) null else SLLNode(carry)
> this == null -> node.also { it!!.value += carry } // Smart cast doesn't work here.
> node == null -> this.also { value += carry } // Works here.
> else -> {
> ...
> }
> }
> 
> ```

I ran across this and was going to reply some optimization to that code, but it occurred to me that the real issue is an incomplete design. In reality you should be using immutable data structures, not mutable ones, but I will stick with mutable.

What you need is this method:

```auto
operator fun SLLNode?.plusAssign(operand: Int): SLLNode? =
    when {
        operand == 0 -> this
        else -> this?.also { value += operand } ?: SLLNode(operand)
    }

```

Then your original code just becomes:

```auto
fun SLLNode?.sumListWith(node: SLLNode?, carry: Int = 0): SLLNode? =
    when {
        this == null -> node += carry
        node == null -> this += carry
        else -> {
            ...
        }
    }

```
