Lambda DSLs and infinite loops

I’m not sure if this is a bug, but it’s quite odd.

If I do

fun foo(): Int {
    while (true) {
        if (doSomeWork()) return 42
    }
}

this compiles fine, because when (if) this function returns, it returns an int.

However if I try to do this in a lambda body

fun foo(): Int {
    return run<Int> {
        while (true) {
            if (doSomeWork()) return@run 42
        } // Type mismatch. Required: Int; Found: Unit
    }
}

the compiler complains that the body returns Unit instead of Int.

Throwing an exception after this loop fixes the problem, but the compiler will now (rightfully) complain that the exception is never thrown… which implies that it should’ve compiled in the first place.

fun foo(): Int {
    return run<Int> {
        while (true) {
            if (doSomeWork()) return@run 42
        }
        throw IllegalStateException() // Unreachable code; Throwable instance 'IllegalStateException' is not thrown 
    }
}

This is highly simplified; I’m actually running into this problem with coroutine builders, but the issue is the same.

(Kotlin 1.3.72)

ah, kotlin doesn’t realise while true doesn’t return…
But, we can create or own functions…

If you want to say that something doesn’t return, you use Nothing.
Therefor, you can create a function runForever

inline fun runForEver(
    lamb: ()->Unit
) : Nothing {
    while(true) lamb()
}

fun foo(): Int {
    return run {
        var i = 0;
        runForever{
            if (i == 10) return@run i
            i++
        }
    }
}
fun main() = println(foo()) // this prints 10

This is an oportunity for the type inference to improve a bit :slight_smile:

Found the topic on youtrack: https://youtrack.jetbrains.com/issue/KT-27970

I would agree, but the thing is, it does realize that it never returns, because it works fine when not in a lambda expression as mentioned in the linked issue.

I guess I’ll refactor this into an extra function as mentioned for now.

1 Like