We know the lambda body is lazily well, because if we don't call the lambda the code in the lambda body is never be called.
We also know in any function language that a variable can be used in a function/lambda even if it is not initialized, such as javascript, ruby, groovy and .etc, for example, the groovy code below can works fine:
def foo
def lambda = { foo }
foo = "bar"
println(lambda())
// ^--- return "bar"
We also know we can access an uninitialized variable if the catch-block has initialized the variable when an Exception is raised in try-block in Java, for example:
// v--- m is not initialized yet
int m;
try{ throw new RuntimeException(); } catch(Exception ex){ m = 2;}
System.out.println(m);// println 2
If the lambda is lazily, why does Kotlin can't use an uninitialized variable in lambda? I know Kotlin is a null-safety language, so the compiler will analyzing the code from top to bottom include the lambda body to make sure the variable is initialized. so the lambda body is not "lazily" at compile-time. for example:
var a:Int
val lambda = { a }// lambda is never be invoked
// ^--- a compile error thrown: variable is not initialized yet
a = 2
Q: But why the code below also can't be working? I don't understand it, since the variable is effectively-final in Java, if you want to change the variable value you must using an ObjectRef
instead, and this test contradicts my previous conclusions:"lambda body is not lazily at compile-time" .for example:
var a:Int
run{ a = 2 }// a is initialized & inlined to callsite function
// v--- a compile error thrown: variable is not initialized yet
println(a)
So I only can think is that the compiler can't sure the element
field in ObjectRef
is whether initialized or not, but @hotkey has denied my thoughts. Why?
Q: why does Kotlin inline functions can't works fine even if I initializing the variable in catch-block like as in java? for example:
var a: Int
try {
run { a = 2 }
} catch(ex: Throwable) {
a = 3
}
// v--- Error: `a` is not initialized
println(a)
But, @hotkey has already mentioned that you should using try-catch
expression in Kotlin to initializing a variable in his answer, for example:
var a: Int = try {
run { 2 }
} catch(ex: Throwable) {
3
}
// v--- println 2
println(a);
Q: If the actual thing is that, why I don't call the run
directly? for example:
val a = run{2};
println(a);//println 2
However the code above can works fine in java, for example:
int a;
try {
a = 2;
} catch (Throwable ex) {
a = 3;
}
System.out.println(a); // println 2