Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Using outer class's val/methods as defaults in nested data class declaration

Consider the following toy example:

class A{
    val a=1

    fun hello() =println("hello")

    init {
        println(a)
        println(this::hello)
    }

    data class B(val b: Int = a, val func: () -> Unit = this::hello)
}

This doesn’t compile, linting the errors: Unresolved reference: a and 'this' is not defined in this context. This confuses me, since they are available inside the preceding init.

Why are the vals/vars/methods of the parent not accessible in the data class declaration, even though it’s nested?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

In spite of the plethora of SO questions matching "*kotlin*nested*data*", I couldn’t find one answering this.

>Solution :

There are two different kinds of classes that can be declared inside another class:

  • Nested classes: These are just simple class definitions without any connection to the enclosing class except that they must be explicitly qualified with the outer class:

    fun someUnrelatedFunction() {
        val b = A.B()
    }
    

    That’s what you have: Two independent classes, two independent instances, two independent this objects. Therefore you cannot access this of the outer class.

  • Inner classes: Inner classes on the other hand can only exist with an instance of the outer class. That means that they cannot be instantiated on themselves. Usually the objects of an inner class are created by the outer class. And in that case the instance of the outer class is available and it can be accessed by ther inner class:

    class A {
        val a = 1
    
        fun hello() = println("hello")
    
        init {
            println(a)
            println(this::hello)
        }
    
        inner class B(val b: Int = a, val func: () -> Unit = this::hello)
    }
    

    This will compile now, because B is defined as an inner class. Note that data classes cannot be inner classes, so I removed data.

    Although this works now, the following doesn’t anymore:

    fun someUnrelatedFunction() {
        val b = A.B()
    }
    

    The compiler complains with this error message:

    Constructor of inner class B can be called only with receiver of containing class

    Instead you can create the following property in class A:

    val b = B()
    

Read more in the documentation about Nested and inner classes.

As a closing note, since you talked about parent class in your question: Parent classes only exist in inheritance hierarchies where one class extends another. That is entirely unrelated though and has nothing to do with the code from your example. Your code is about an outer and an inner/nested class, not about parent and child classes.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading