Data class override parameters with Enum error

Hello, I have an inheritance:

data class A(override val p1: MyEnum = MyEnum.First): B

open class B(open val p1: MyEnum? = null)

While it’s fine to compile, p1 is not overrided properly here until I do the actually same type: override val p1: MyEnum?

Throws as a bug for me with java.lang.ExceptionInInitializerError

Something weird happens with Enum. All other parameters are fine to override but I have null in the Enum on debug while test shows all is ok.
And I got the runtime error if make the parameter non-nullable in class B.
Works with simple classes also (and you actually, don’t need to override, the error happens just with plain Enum).

Are you sure you use the right B and not some other type? Your above code should not even compile, because you didn’t invoke constructor of B in A. Could you provide a full reproducible example?

Also, overriding a property that has a backing field seems like a code smell to me. This way both B and A create their own p1 field, but the one from B is just not used. Maybe you should make B.p1 abstract or make B at all an interface?

As I wrote in addition, you even don’t need to inherit the parameter. (And yes, I didn’t understand, what’s the profit to override the parameters in constructor instead of other methods).

open class Building(
    val category: BuildingCategory = BuildingCategory.NONE,
)

open class House : Building(
    category = BuildingCategory.HOUSING,
)

    @Test
    fun buildingCategory() {
        val house = House()
        assertEquals(BuildingCategory.HOUSING, house.category)
    }

-> java.lang.ExceptionInInitializerError

Your code should work as you expect: Kotlin Playground: Edit, Run, Share Kotlin Code Online I suspect your problem is somewhere else.

How did you launch it without knowing what the Enum implementation is?
But yes, it looks workable there.

So you suspect the problem may be related to the implementation of your enum, but you still decided to not provide it neither in your question and even after I asked for a reproducible example. What do you expect people to do if they don’t see the code?

2 Likes

I got the error with this code

enum class BuildingCategory(val buildings: List<Building>) {
    HOUSING(
        listOf(House())
    ),
    NONE (
        listOf()
    )
}

Exception in thread "main" java.lang.ExceptionInInitializerError

P.S. If I don’t do override in the data class, there is Data class must have at least one primary constructor parameter error.

And now we have everything we need to determine what’s the problem in your code. You have a circular reference between House and HOUSING. In order to initialize HOUSING we need to initialize House, but to initialize House we need to have HOUSING initialized already.

Honestly, it seems pretty strange that we can create many different instances of House, but HOUSING keeps a very specific instance for itself. Why do you need this buildings property? Why do you need House class and HOUSING enum separately? Maybe you should use sealed classes instead of enums?

2 Likes

I need a simple single structure to store all the needed data.

enum class BuildingCategory(@StringRes val typeRes: Int, val icon: ImageVector, val buildings: List<Building>)

What is the better solution? How can I also get all the classes of same type in one loop?

P.S. Heard, sealed classes are verbose under the hood and it looks to me, it’s not so plain for my case.

P.P.S. The second question was - how to avoid this without code duplications?

If I don’t do override in the data class, there is Data class must have at least one primary constructor parameter error.

I split my Enum to Enum and a map of instances. But it’s also possible to change instances to classes and then create instances (should be a higher resource-consumption way because of multiple usage). Anyway, I need to make copies and creating new instances of them because of specifics of data classes.

Data class must have at least one primary constructor parameter is still looks messy, will see how to make a better workaround.

Why would want a data class with no parameters?

data classes just create an equals toString and hashCode functions with the constructor parameters. Hence for a class whose constructors has no parameters, equals would always return true, toString would return the class name, and hashCode would return some constant.

Maybe I just don’t want to duplicate the code and make it the way I worte before

Why does this need to be a data class?

All instances of this class are identical.
This can be an object.

2 Likes

Yes, not sure now if it should be data, just a class.

why not an object?

1 Like

Don’t need a singleton here. There should be many instances.

This class doesn’t have any mutable state.
The constuctor takes no parameters, and there are no setters.
All instances are indistiguishable from one another, this is functionally a singleton.

3 Likes