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 AM