Why does `b()` produces more complex bytecode than...
# compiler
l
Why does
b()
produces more complex bytecode than
a()
, instead of just adding a private field to the anonymous class?
Copy code
fun interface Counter {
    fun getAndIncrement(): Int
}

fun a(): Counter = object : Counter {
    var number = 42
    override fun getAndIncrement(): Int {
        return number++
    }
}

fun b(): Counter {
    var number = 42
    return Counter { number++ }
}
s
Within
b()
you’re not defining an anonymous class, but it’s just lambda definition of the single abstract method. So the compiler needs to treat it like a variable capture that could be coming from anywhere.
I guess it would be possible to write a more optimised version, depending on what scope the capture variable is coming from.
l
But that's becoming an anonymous class in the bytecode anyway
s
The captured variable could also be a property of a surrounding class, or anything else.
l
So it seems like an unnecessary wrapper
If it's from a surrounding class, I think a reference to that class instance is kept instead
s
Wasn’t aware the compiler was already taking this into account. I thought it was doing to most naive thing always.
So is it here generating an anonymous class that surrounds the counter to pass the reference?
l
I don't see how it could work otherwise for the surrounding class thing. You don't want 2 disconnected variables, so the only sensible solution is to keep what owns the variable.
In b, wraps the number variable inside an extra object instead of doing like b does.
s
Thanks for clarifying. Now I’m curious too if there is a reason for this 😅
y
Might be something related to invoke-dynamic and the like not having support for capturing (afaik)
s
If you are talking about ref wrapping, it only happens because of
var
, I believe. You can potentially use the variable outside of captured scope (e.g. in
b
body), so compiler does the simplest thing
y
I'd be interested to see if a minifier like Proguard would deal well with that. Maybe also the JVM escape analysis would be able to get rid of the ref wrapper
s
Tbh r8/proguard are probably not smart enough, but JIT might be