Home > Blockchain >  How should I handle logically unreachable code
How should I handle logically unreachable code

Time:04-28

I have a class implementing an interface which forces me to implement 2 methods - fun check(): Boolean and fun onCheckFalse(): Int.

The usage looks something like:

if (check().not()) return onCheckFalse()

In my implementation, I always return true from check() so onCheckFalse() becomes logically unreachable.

What should I do there?

  1. Return some value even if it has no logical meaning?
  2. Throw an exception? Which one?
  3. Something else?

The specific use-case is for kotlin, but a general answer is of course welcome as well.

CodePudding user response:

It's not uncommon to be forced to implement an interface method that makes no sense in a particular implementing class*.

The usual approach in Java — and hence in Kotlin/JVM — is to throw UnsupportedOperationException; see this question. That way, if someone does unwittingly call your method, they'll find out the hard way that your class doesn't provide that functionality!

In the particular case that the method is a notification or callback — called for the class's own benefit, and not to provide any functionality to the caller — then there's no point telling the caller that it's not implemented, so the best approach there is simply an empty method that does nothing.

(However, OP has clarified that the latter doesn't apply in this particular question, despite the on…() method name.)


* The original use case for UnsupportedOperationException is for immutable collections: in Java, the same interface (e.g. java.util.List) is used for both mutable and immutable collections, and so the mutating methods are specified to throw that exception when called on immutable collections.

Of course, that particular case doesn't apply in Kotlin, which splits those interfaces into two: a read-only super-interface (e.g. List), and a sub-interface (e.g. MutableList) which adds in the mutating methods.

But there are other situations in which an implementation may not be able to implement certain methods. For example, a non-transactional database class may not be able to roll back changes, or an image without an alpha channel may not be able to set transparency.

I think that exception gets over-used, though. If your class can implement the action in some cases but not others — as in many of the examples I found online — then it would probably be more logical and helpful to throw IllegalArgumentException or IllegalStateException instead.

And ideally, an interface would be designed so that no implementations would ever need to throw UnsupportedOperationException. The List example shows that although Kotlin's collection interfaces are a little more complex than Java's, they're more expressive; you can tell at compile time whether you have a read-only collection or a read/write one, which avoids a whole class of run-time errors. So if you're designing interfaces, it's worth thinking ahead and trying to avoid the need if you can.

  • Related