Compile time checked intialization in inline functions

Not sure if i’m using the right word, but by compile time checked initialization I mean this:

// this compiles
fun main() {
    var x: Int
    x = 10
    println(x)
}

I would like the language to support a case like this:

// this doesn't compile
fun main() {
    var x: Int
    unsuspendable {
        x = 10
    }
    println(x)
}
inline fun unsuspendable(block: () -> Unit) = block()

The purpose of unsuspendable is we have large blocks of code in a suspend function, and we basically want to mark off critical sections to make sure people get a compile time error if they try to add some suspend code there. There are work-arounds to this (like having unsuspendable return things), but I think it would be cool if this worked.

Contracts allow this:

fun main() {
    var x: Int
    unsuspendable {
        x = 10
    }
    println(x)
}
inline fun unsuspendable(block: () -> Unit) {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
}
2 Likes

Thank you this is perfect!

For anyone else who sees this. I made a mistake making the function inline, because then it gets its suspendability from the outside scope. Here’s the final version of unsuspendable:

fun main() {
     runBlocking {
         var x: Int
         unsuspendable {
             // delay(100) // throws a compile error
             x = 10
         }
        println(x)
    }
}
fun unsuspendable(block: () -> Unit) {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
}

A variation is to add a generic return value.

1 Like

In fact, you can still make it inline, but then make the parameter crossinline, which effectively prevents the suspendability being inherited from outside like this:

fun main() {
     runBlocking {
         var x: Int
         unsuspendable {
             // delay(100) // throws a compile error
             x = 10
         }
        println(x)
    }
}
inline fun unsuspendable(crossinline block: () -> Unit) {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
}
1 Like

Hmm interesting. Ya the downside is it prevents nonlocal returns, which I don’t want to do.

1 Like

Non-local returns, AFAIK, are also prevented if you use a normal (i.e. non-inline) fun with a lambda parameter.