Why outer class cannot see private members of inner class?


What was the reason to diverge from Java in this point? I can’t seem to find the rationale in the docs or on this site.


Probably because the JVM actually can’t and Java generates appropriate synthetic accessors. Kotlin just tries to limit the idea in the first place.


Wow, I didn’t know that. Still, why can’t Kotlin do the same? It isn’t that language designers shy away from generating bytecode :slight_smile:

Suppose there’s a tree type and a tree node type. You want to allow modifying node pointers only from the tree code, because it preserves some invariants. In Java, you can simply make the Node a (static) inner class of Tree, make the pointer fields private, have a public getter and then either use a private setter or simply manipulate the pointer from the Tree class. Seems like there’s no good way to do that in Kotlin.

class Tree {
  private val root = Node()

  fun move(node: Node, after: Node) {
    // Need to manipulate pointers while maintaining invariants.
    // E.g. need to say after.nextSibling = node, but how?

  class Node(
    parent: Node? = null,
    firstChild: Node? = null,
    nextSibling: Node? = null
  ) {
    var parent: Node? = parent; private set
    var firstChild: Node? = firstChild; private set
    var nextSibling: Node? = nextSibling; private set


In most cases you can get away with making the type itself private. In your case you’ll have to go the extra way by having a Node interface and a NodeImpl class (which is private). Btw. trees are typically implemented immutable (but indeed don’t have to).


Just declare your node impl as a private top level class in the same file.


The point is that in a tree you would want your node to be public but have members which can only be accessed by the tree itself, so your node can not be just private


The solution (admittedly not quite perfect) is to have the following:

class Tree {
  val root: Node = NodeImpl

  fun move(node: Node, after: Node) { /* some impl */ }

  interface Node {
    val parent: Node?
    val firstChild: Node?
    val nextSibling: Node?

  private class NodeImpl(override var parent: NodeImpl? = null,
                         override var firstChild: NodeImpl? = null,
                         override var nextSibling: NodeImpl? = null): Node


This should work although it doesn’t stop “invalid” nodes from being passed in by users, but node ownership is always a problem in mutable trees (copying to a locally created not is always safer in that sense).


If you are separating your code into different modules you can even use an abstract class with an internal constructor instead of the interface. That way no one outside of the module can create “invalid” nodes.


Oh, I see. I somehow missed that you can override val with var. Thanks!

As for stopping from passing “invalid” nodes — Node can be a sealed interface


You’re right. I did forget about sealed as I have not used it myself so far :slight_smile:


Kotlin allows to do that but uses different default behavior.
Inner class in Kotlin by default behave like Java’s class with static modifier on inner class. So it’s completely separate class without reference to the parent.
If you want to get access to parent class like in java without static you should add modifier inner to Kotlin’s internal class.
It just forces you to be more explicit for such case and it’s harder to leak parent class accidentally like in java, when you just forgot to mark inner class static, it’s actually not the best practice in most cases