Xad Kile
11/09/2022, 12:51 PMobject MyObject{ }
). In my app, there's a snippet that looks like this
fun myFunction():Any{
try{
// do things
}catch(e:Throwable){
return MyObject.sideEffect()
}
}
object MyObject{
fun sideEffect():Any{
//....
}
}
the code inside the try block will throw an StackOverflowError under certain condition. The StackOverflowError is caught, and a side effect is emitted. This side effect is produced by an object declared in a different file, and half of the time, it will throw this exception; while on the other half, it runs just fine.
Could not initialize class com.example.MyObject
java.lang.NoClassDefFoundError: Could not initialize class com.example.MyObject
However, if I run this val mo = MyObject
before calling myFunction()
, the NoClassDefFoundError
exception is never thrown.
Maybe this has something to do with the fact that MyObject is lazily allocated according to the official document. Could someone point me to a more in-depth document on object declaration? I need to know what is going on badly 🫠 Thank you.ephemient
11/09/2022, 2:49 PMephemient
11/09/2022, 2:50 PMRoukanken
11/09/2022, 2:57 PMmyFunction
is actually recursive.
You then catch it at lowest levels (when calling myFunction()
would throw SO) and ignore the fact that your stack is most likely near-full and you call an another function. Which will just likely throw a SO again...
Example:
fun myFunction(depth: Int) {
try {
myFunction(depth + 1)
} catch (e: Throwable) {
println("$depth: $e")
MyObject.sideEffect()
}
}
object MyObject {
fun sideEffect() {
println("side effect")
}
}
fun main() {
myFunction(0)
}
Output:
9856: java.lang.StackOverflowError
9855: java.lang.StackOverflowError
9854: java.lang.StackOverflowError
9853: java.lang.StackOverflowError
9852: java.lang.StackOverflowError
9851: java.lang.StackOverflowError
9850: java.lang.StackOverflowError
9849: java.lang.StackOverflowError
9848: java.lang.StackOverflowError
9847: java.lang.StackOverflowError
9846: java.lang.StackOverflowError
9845: java.lang.StackOverflowError
9844: java.lang.StackOverflowError
9843: java.lang.StackOverflowError
9842: java.lang.StackOverflowError
9841: java.lang.StackOverflowError
9840: java.lang.StackOverflowError
9839: java.lang.StackOverflowError
side effect
ephemient
11/09/2022, 3:00 PMephemient
11/09/2022, 3:01 PMJoffrey
11/09/2022, 4:27 PMThrowable
unless you really know what you are doing and have carefully considered and decided that it makes sense to catch an OutOfMemoryError
, NoClassDefFoundError
, StackOverflowError
and the likes. Most likely it doesn't.
In this specific case, it seems you decided to catch StackOverflowError
on purpose, and it's unclear why. If you ran into a stack overflow error, there is likely a bug in a recursion that should be fixed instead of caught.Xad Kile
11/10/2022, 2:10 AMephemient
11/10/2022, 4:41 AMsealed class Expr {
data class Literal(val value: Int) : Expr()
data class Add(val a: Expr, val b: Expr) : Expr()
}
fun eval(expr: Expr): Int = when (expr) {
is Expr.Literal -> expr.value
is Expr.Add -> eval(expr.a) + eval(expr.b)
}
val evalDeep = DeepRecursiveFunction<Expr, Int> { expr ->
when (expr) {
is Expr.Literal -> expr.value
is Expr.Add -> callRecursive(expr.a) + callRecursive(expr.b)
}
}
fun main() {
val expr = (1..10_000).fold(Expr.Literal(0)) { acc: Expr, value -> Expr.Add(acc, Expr.Literal(value)) }
println(runCatching { eval(expr) }) // => Failure(java.lang.StackOverflowError)
println(runCatching { evalDeep(expr) }) // => Success(50005000)
}
Xad Kile
11/10/2022, 10:09 AM