Probably a pipe dream, but it would be nice if the...
# language-proposals
r
Probably a pipe dream, but it would be nice if there were a mechanism to make a `data class`'s
copy
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.
Example:
Copy code
data 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.
As it is you have to do this:
Copy code
data 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.)
h
Do you really need to throw/create an Exception? I would love to see optional init from Swift, so you could simple return `null`/`nil` in the
init
block instead, which is more kotlinisher IMHO.
👎🏻 1
r
It doesn't need to be an exception particularly. And I'd be happy for
copy
to delegate to an
operator fun invoke
that returns... well, anything really, if the data class's constructor is private.
But if you want the caller to be able to know why the operation didn't succeed, yes, you need more than just
null
. 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.