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 effectephemient
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