Data class with private constructor

Data classes are quite useful, and I’ve had scenarios where I want to have a data class with a private constructor because I want to use a factory pattern to create objects of this class AND I want to get the benefits of a data class (generated toString, hashCode, equals, etc.), but there is a problem.

Problem: The private constructor is publicly exposed via the data class generated copy function.

Proposal: When a data class has a private constructor, the compiler shouldn’t generate a copy function.

Currently, you can make a data class with a private constructor and just ignore the reality that the constructor is not truly private, which is not nice and potentially makes your factory very bug/error prone. Or alternatively you can write a non-data class with a private constructor but then you’ll manually have to write functions like toString, hashCode, equals, etc. which works but is a lot of boilerplate so it’s not nice either.

2 Likes

I like the general idea, but I would generate copy() function with the same visibility as primary constructor instead of simply not generating them at all.

7 Likes

This is actually a very well known issue, discussed here:
https://youtrack.jetbrains.com/issue/KT-11914/Confusing-data-class-copy-with-private-constructor
I think the best idea is to make copy() mimic visibility of the constructor.
As it is, the best workaround I know of is the private data class idiom: make a sealed class with abstract properties with a nested private data class implementing those. Too much boilerplate, yes, but at least once it’s done it’s more or less robust.

2 Likes