Rob Elliot
04/28/2022, 10:14 PMcopy
method delegate to an operator fun invoke
on the class's companion object
that took the same parameters but was able to return a more flexible return type.
It's a shame that you have to put all the invariant checking in the data class's init
, and so have to fail it with exceptions.Rob Elliot
04/28/2022, 10:22 PMdata class Foo private constructor(val x: Int, val y: Int) {
companion object {
operator fun invoke(x: Int, y: Int): Result<Foo> =
if (x < y) Result.failure(Exception("oh no"))
else Result.success(Foo(x, y))
}
}
It would be nice if Foo(2, 1).copy(y = 3)
returned a Result<foo>
, instead of a Foo
bypassing the invariant check.Rob Elliot
04/28/2022, 10:25 PMdata class Foo(val x: Int, val y: Int) {
init {
require(x >= y)
}
}
and callers only find out at runtime that it can go wrong.
(Of course you could keep the constructor private and have the operator fun invoke as well, and have the init
check just for when copy
is called, but duplicating the checks feels very in elegant and it all starts to get a bit noisy when one of the joys of data classes is how little syntax they require.)hfhbd
04/29/2022, 9:56 AMinit
block instead, which is more kotlinisher IMHO.Rob Elliot
04/29/2022, 10:00 AMcopy
to delegate to an operator fun invoke
that returns... well, anything really, if the data class's constructor is private.Rob Elliot
04/29/2022, 10:01 AMnull
. Personally I'm not a fan of things that just silently don't work without telling you why. And it may be that the caller can behave differently depending on the details of why it failed.