hi everyone. If there is an exception “myException...
# getting-started
g
hi everyone. If there is an exception “myException” and my code can throw either “myException” or another exception that has a cause “myException”. Is it possible for the catch block to catch those situations? i.e. catch when the exception is “myException” or some other exception that has cause “myException”? I.e. smth like
catch (cause is myException)
r
you cannot catch an exception based on the 'root cause', so you'd have to catch the actual exception, check the cause and if the cause is not
MyException
, rethrow it
a
I don’t think there’s anything built in, but here’s a quick demo showing how to get all exceptions + causes by using a Sequence. It will recursively fetch the cause, until the cause is
null
Copy code
try {
  // ...
} catch (ex: Exception) {
  val allCauses = generateSequence<Throwable>(ex) { ex.cause }
}
You might want to consider checking suppressedExceptions too?
g
so essentially I have to write a utility function and use it smth like this: https://pl.kotl.in/4de-VgpHE
a
tbh I think checking like this has the air of code smell. Rather than returning failure states via exceptions, what about returning a custom result wrapper?
Copy code
sealed interface MyOperationResult {
  class Success(...) : MyOperationResult
  class Failed(...) : MyOperationResult
}
g
@Adam S you mean, not to use exceptions as return values
a
yes, so instead of throwing an exception, return
MyOperation.Failed(...)
the Kotlin stdlib has a Result type, but it’s usually more clear to do it yourself
so essentially I have to write a utility function and use it smth like this:
https://pl.kotl.in/4de-VgpHE
yes basically, but I’d refactor it a little bit:
Copy code
fun main() {
  try {
    // ...
  } catch (ex: Exception) {
    val allCauses = generateSequence<Throwable>(ex) { ex.cause }
    val myException = allCauses.filterIsInstance<MyCustomException>().firstOrNull()
  }
}

class MyCustomException : Exception()
g
@Adam S and if there are multiple failure causes then the operation result type will look like this, right?
Copy code
Success
Failure1
Failure2
...
so that I can make decision based on the type of the failure
a
yes, that makes sense to me
g
cool thanks
a
just to give another option, you could also add additional properties into a single Failure response, and then make a decision based on those properties:
Copy code
sealed interface MyOperationResult {
  class Success(...) : MyOperationResult
  class Failed(
    val attempts: Int, // if attempts < 100, then maybe retry
    val invalidProperties: Int, // if invalidProperties > 0, then there's no way to recover, so abort immediately 
  ) : MyOperationResult
}
there’s no correct answer, so it depends on your situation. I thought I’d suggest an alternative, in case it’s useful.
g
ah thanks that’s indeed is a good alternative to have in case
what I feel is that exception will still be inside the
Failed
value. So I will end up comparing exception types. Because the origin of those failures are exceptions. Or I need to create a parallel indicators (?)enum and set them when respective exception is thrown and then compare to those indicators. Anyway, thank you
a
you’re welcome! Sounds like you’ve got some good options to compare
❤️ 1
c
A good rule of thumb I find is to use exceptions for something that you haven't foreseen or something has gone badly wrong and your program needs to recover from it in some way. For something that is a known thing that can go wrong (user doesn't exist in database, doesn't have permission for something, etc) these aren't exceptional, they're expected. So a return type as described above is probably a better solution. Don't use exceptions for program flow where possible.
👍 1
g
@Charles Flynn thanks for the suggestion. Looking more into this thing, I think the rule can be the following: • on producer side: throw exceptions for stuff clients will just rethrow, otherwise return a value of
Result
type. A bit of a problem here is that standard result type requires an exception value, so an exception value must be used to indicate the kind of the failure happened • on consumer side: ◦ if producer returns a
Result
type value, then process error values if any, use
is
,
as
if you need to further discriminate
exception
value by type. Unfortunately there is no generic way at looking at the cause of exception, so that need to be implemented manually if required. ◦ if producer throws an exception, figure out what are recoverable and unrecoverable exceptions, recover from recoverable ones, re-throw all others.
what concerned me a bit is that in “kotlin in action” I have not found usages or mentions of the
Result
type. That makes me think that returning
Result
type type value approach or not standardised or not intended/envisioned by the language creators. But that type in the standard library, so quite confusing.
c
Generally I make my own types up rather than use Result
g
Hi all, sorry for digging out this old thread. What library would you recomment for Result type that works both in java and kotlin?