I'm struggling a little bit to understand how this...
# random
s
I'm struggling a little bit to understand how this is allowed:
Copy code
fun 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?
s
The way I understand it is that in cases like these, synthetic accessors are generated in the effective bytecode. In this example, when
greet
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):
Copy code
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();
   }
}
s
Wow, that actually makes a lot of sense! Thanks for the exaplanation!