sindrenm
06/11/2025, 4:05 PMfun main() {
val foo = Greeter("World")
foo.greet()
}
class Greeter(private val receiver: String) {
internal inline fun greet() {
println("Hello, $receiver")
}
}
Doesn't this effectively “leak” the private val receiver: String into main when it's inlined? If I remove internal, it fails with the expected error, but how is internal and private “the same” here?Szymon Jeziorski
06/12/2025, 10:02 AMgreet is inlined, the synthetic accessor with public visibility is called to obtain receiver value.
As for the internal vs public there, when internal is used, compiler has full control of the synthetic method generated (so it can apply whatever name mangling it wants for example) as it's only ever called from within the same compilation unit as the one that generates it.
If public was used and we would want to call this code from some other compilation unit, that other compilation unit would need to know details about the generated synthetic method in order to inline greet properly, and that I believe would be against the semantics of synthetic accessors.
If you would decompile the snippet you provided, you would see something like this (simplified it a little):
public final class Greeter {
@NotNull
private final String receiver;
[...]
// $FF: synthetic method
public static final String access$getReceiver$p(Greeter $this) {
return $this.receiver;
}
}
[...]
public final class FileNameKt {
public static final void main() {
Greeter foo = new Greeter("World");
System.out.println("Hello, " + Greeter.access$getReceiver$p(foo));
}
// $FF: synthetic method
public static void main(String[] args) {
main();
}
}sindrenm
06/13/2025, 8:47 AMlouiscad
06/23/2025, 1:03 AM