Why won't this inline job compile when its lambda runs inside a Runnable?
job is inline and returns a Runnable that calls the inlined lambda inside another lambda (executeTask). It does not compile. Fix the signatures so the code builds while keeping job inline where it helps.
fun executeTask(task: () -> Unit) {
println("before task"); task(); println("after task")
}
inline fun job(job: () -> Unit): Runnable {
return Runnable { executeTask(job) } // does not compile
}
fun main() {
val executor = Executors.newSingleThreadExecutor()
executor.submit(job { println("hello task") })
}
Find and fix the bug.
An inlined lambda may do a non-local return, which is illegal inside the nested Runnable. Mark the parameter crossinline job: () -> Unit to forbid that return, so the lambda may run inside the Runnable. Or drop inline from job.
- ✗Assuming any inline lambda can be called from anywhere, including a nested object
- ✗Reaching for
noinlinewhen the lambda actually needscrossinline - ✗Blaming the Java SAM conversion instead of the non-local-return rule
- →How does
crossinlinediffer fromnoinlinefor a lambda parameter? - →Why is a non-local return illegal inside the
Runnablebody specifically?
The bug
job is inline, so its lambda parameter permits a non-local return by default. But the lambda is invoked inside a Runnable object — a separate execution context where a non-local return is illegal. The compiler rejects it.
inline fun job(job: () -> Unit): Runnable {
return Runnable { executeTask(job) } // ❌ job could do a non-local return
}
The fix
Mark the parameter crossinline. That forbids the non-local return, so the lambda is allowed to run inside the Runnable while job's body stays inlined.
inline fun job(crossinline job: () -> Unit): Runnable {
return Runnable { executeTask { job() } } // ✅
}
The alternative is to drop inline from job entirely: the lambda then becomes an ordinary object and the non-local-return problem disappears.