This is because use
is an inline function, which means the lambda body will be inlined to the call-site function, and the actual type of the variable myVar
depends on its context.
IF the myVar
is used in lambda for reading, the the type is MyType
or its supertype. for example:
// v--- the actual type here is MyType
var myVar: MyType = TODO()
autoClosable.use {
myVar.todo()
}
IF the myVar
is used in lambda for writing, the actual type is an ObjectRef
. why? this is because Java don't allow you change the variable out of the annoymous class scope. In fact, myVar
is effectively-final. for example:
// v--- the actual type here is an ObjectRef type.
var myVar: MyType
autoClosable.use {
myVar = autoClosable.foo()
}
So when the compiler checking at println(myVar)
, it can't sure the element of the ObjectRef
is initialized or not. then a compiler error is raised.
IF you catch anything, the code also can't be compiled, for example:
// v--- the actual type here is an ObjectRef type.
var myVar: MyType
try {
autoClosable.use {
myVar = it.foo()
}
} catch(e: Throwable) {
myVar = MyType()
}
// v--- Error: Variable 'myVar' must be initialized
println(myVar)
But when the actual type of the myVar
is MyType
, it works fine. for example:
var myVar: MyType
try {
TODO()
} catch(e: Throwable) {
myVar = MyType()
}
println(myVar) // works fine
Why kotlin didn't optimize inline functions to use MyType
directly for writing?
the only thing I think, the compiler don't know the myVar
whether is used in lambda body of another uninline function in future. or kotlin want to keep semantic consistent for all of the functions.