interface IPoint {
val x: Float
val y: Float
fun copy(x: Float = this.x, y: Float = this.y) = Point(x, y)
}
data class Point(
override var x: Float,
override var y: Float
) : IPoint
Gives me a warning: Function 'copy' generated for the data class has default values for parameters, and conflicts with member of supertype 'IPoint'
I can suppress the Warning using
@Suppress("DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING")
But are there any better approaches?
I would suggest to revisit the need to have an interface in the first place. What would be the other implementations of this interface? What copy
is supposed to do for those other implementations? Are they going to be returning copy of themselves, or use a default implementation of copy
from the interface and return an instance of Point
? In the later case it does not seem appropriate to name it copy
. The better name would be toPoint
. So, to recap, if you really need the interface (e.g. you have multiple impls), then you might consider renaming copy
in the interface, otherwise just drop the interface altogether and use data class directly.
The main point of IPoint
is to define a read-only interface. Much like with List
and MutableList
.
So, when a function takes an IPoint
the caller can pass in a point and be certain that it won’t be mutated.
Currently, Point
is the only concrete implementation of IPoint
.
copy
is supposed to always return a Point
.
I assumed the name toPoint
makes it less clear that its creating a mutable copy.
But looking at Collection<T>.toMutableList()
and others, to...
seems to commonly mean copying in the Kotlin APIs.
You can make your Point class immutable like this: data class Point(val x: Float, val y: Float)
. No need to have a dedicated interface for immutability.
I know that’s possible, but I often need a mutable Point
to avoid object creation. My main usage scenario is game development.
To still buy a bit of type safety I use IPoint
where I know no mutation will happen.