Is there a reason for not allowing inner+data classes?


#1

Can’t see why this is not a “valid” combination.
Thanks


#2

Inner classes have a hidden reference to an instance of the outer class, from which they were instantiated.
When an inner class is also a data class, this leads to a question, whether that reference is one of the data class component properties?
And whether that reference affects how the functions equals, hashCode, toString, componentN of the data class are generated depends on the answer on this question.


#3

I’m curious: what kind of useful design does this restriction prevent?

My gut feeling is that data classes should stand on their own. If they depend on state of an outer object, they are not really a data classes, right?


#4

Actually this comes from another restriction I’ve asked before in forum: Private classes in “parallel” files in same package

i.e. : I didn’t need the class to be inner : I actually wanted it to be module private, but be named with same name in multiple files, which as mentioned above doesn’t work. So making it inner was just a workaround to avoid the name clash…

Cheers


#5

You can simply make it nested inside another class. Nested classes can be data classes.


#6

In Java terms these would be static inner classes (have access to private members of the outer class but don’t hold an instance reference)


#7

Thanks. I understand now the difference. Is taking me some time to get familiar with all the new qualifiers… That solves problem.

Thanks


#8

I came across a use for an inner data class. In my case, I need to return multiple values from a function, both of which have a generic type. I’d like to use a destructuring declaration, and a data class is ideal for declaring the named return values and automatically providing componentN() methods. But only an inner class has access to the generic types defined in the outer class.

Since an inner data class wasn’t allowed, I had to either declare componentN() methods myself in a regular inner class. Or alternatively, define the generics again in the data class and pass the outer class definitions through in the return declaration.

For example:

class Foo<T, U> {
    fun bar(): Baz {
        ...
        return Baz(quuz, corge)
    }

    inner class Baz(val qux: T, val quux: U) {
        operator fun component1() = qux
        operator fun component2() = quux
    }
}

Or alternatively:

class Foo<T, U> {
    fun bar(): Baz<T, U> {
        ...
        return Baz(quuz, corge)
    }

    data class Baz<T, U>(val qux: T, val quux: U)
}

If inner data classes were allowed:

class Foo<T, U> {
    fun bar(): Baz {
        ...
        return Baz(quuz, corge)
    }

    inner data class Baz(val qux: T, val quux: U)
}