When and how to use Result in Kotlin? - kotlin

I love the idea of Result.
I love having encapsulated try/catch.
But I’m a little confused about how and when to use Result.
I currently use it like this:
My adapters and services return a Result. Failures and stacktraces are logged but do nothing else
runCatching{
.... // do something cool
}.onFailure {
logger.error("Something bad happened ", it)
}
My Resource classes fold and handle the Result
return service.method().fold(
onFailure = {
Response.serverError().entity("Oops").build()
},
onSuccess = {
Response.ok().entity(doSomethingWith(it)).build()
}
)
Is this really the correct way to use a Result? Or is there a more idiomatic way to code in Kotlin?

TL;DR: never in business code (prefer custom sealed classes), but you can consider Result if you build a framework that must relay all kinds of errors through a different way than the exception mechanism (e.g. kotlin coroutines).
First, there is actually a list of use cases for the motivation of the initial introduction of Result, if you find it interesting. Also in the same document:
The Result class is designed to capture generic failures of Kotlin functions for their latter processing and should be used in general-purpose API like futures, etc, that deal with invocation of Kotlin code blocks and must be able to represent both a successful and a failed result of execution. The Result class is not designed to represent domain-specific error conditions.
Also, here is a very nice article by the lead Kotlin designer about exceptions in Kotlin and more specifically when to use the type system instead of exceptions.
Most of what follows is my personal opinion. It's built from facts, but is still just an opinion, so take it with a grain of salt.
Do not use runCatching or catch Throwable in business code
Note that runCatching catches all sorts of Throwable, including JVM Errors like NoClassDefFoundError, ThreadDeath, OutOfMemoryError, or StackOverflowError. There is usually almost nothing you can do with such JVM errors (even reporting them might be impossible, for instance in case of OOME).
According to the Java documentation, the Error class "indicates serious problems that a reasonable application should not try to catch". There are some very special cases where you might want to try to recover from error, but that is quite exceptional (pun intended).
Catch-all mechanisms like this (even catch(Exception)) are usually not recommended unless you're implementing some kind of framework that needs to attempt to report errors in some way.
So, if we don't catch errors (and instead let them bubble up naturally), Result isn't part of the picture here.
Do not catch programming exceptions in business code
Apart from JVM errors, I believe exceptions due to programming errors shouldn't really be handled in a way that bloats the business code either. Using error(), check(), require() in the right places will make use of exceptions to detect bugs that cannot be caught by the compiler (IllegalStateException, IllegalArgumentException). It often doesn't make sense to catch these exceptions in business code, because they appear when the programmer made a mistake and the logic of the code is broken. You should instead fix the code's logic.
Sometimes it might still be useful to catch all exceptions (including these ones) around an area of code, and recover with a high level replacement for the whole failed operation (usually in framework code, but sometimes in business code too). This will probably be done with some try-catch(Exception), though, but Result will not be involved here because the point of such code would be to delimit with try-catch the high-level operation that can be replaced. Low-level code will not return Result because it doesn't know whether there are higher level operations that can be replaced with something in case of programming errors, or if it should just bubble up.
Modeling business errors
That leaves business errors for result-like types. By business errors, I mean things like missing entities, unknown values from external systems, bad user input, etc. However, I usually find better ways to model them than using kotlin.Result (it's not meant for this, as the design document stipulates). Modelling the absence of value is usually easy enough with a nullable type fun find(username: String): User?. Modelling a set of outcomes can be done with a custom sealed class that cover different cases, like a result type but with specific error subtypes (and more interesting business data about the error than just Throwable).
So in short, in the end, I never use kotlin.Result myself in business code (I could consider it for generic framework code that needs to report all errors).
My adapters and services return a Result. Failures and stacktraces are logged but do nothing else
A side note on that. As you can see, you're logging errors in the service itself, but it's unclear from the service consumer's perspective. The consumer receives a Result, so who's reponsible with dealing with the error here? If it's a recoverable error then it may or may not be appropriate to log it as an error, and maybe it's better as a warning or not at all. Maybe the consumer knows better the severity of the problem than the service. Also, the service makes no difference between JVM errors, programming errors (IAE, ISE, etc.), and business errors in the way it logs them.

Related

How does Kotlin achieve type-safety by eliminating checked exceptions?

I am a newbie to Kotlin programming. While going through the advantages of Kotlin over Java I came across this claim that by avoiding checked exceptions Kotlin achieves type safety. Also I do not understand how the exception handled with an empty catch block harms type-safety(I read it on a blog)?
Can it be explained with an example?
By itself, removing checked exceptions doesn't increase type safety. Kotlin's claim of improved type safety comes from the other features and idioms it introduces to replace checked exceptions.
In Kotlin, exceptions are not intended to be used for recoverable failures. They're only there to handle bugs and logic errors.
As a rule of thumb, you should not be catching exceptions in general Kotlin code.
[...]
Use exceptions for logic errors, type-safe results for everything else. Don’t use exceptions as a work-around to sneak a result value out of a function.
https://elizarov.medium.com/kotlin-and-exceptions-8062f589d07
The "type-safe results" referred to above are things like sealed classes, which provide a very controlled way to enumerate the possible types that a function can return. For example, you could have a sealed class with one implementation for a successful result and other implementations for each of the possible types of failure.
If there’s a single error condition and you are only interested in success or failure of the operation without any details, then prefer using null to indicate a failure. If there are multiple error conditions, then create a sealed class hierarchy to represent various results of your function. Kotlin has all those needs covered by design, including a powerful when expression.
https://elizarov.medium.com/kotlin-and-exceptions-8062f589d07

What should a CoroutineExceptionHandler do with an OutOfMemoryError or other fatal error?

I'm implementing a custom Kotlin CoroutineScope that deals with receiving, handling and responding to messages over a WebSocket connection. The scope's lifecycle is tied to the WebSocket session, so it's active as long as the WebSocket is open. As part of the coroutine scope's context, I've installed a custom exception handler that will close the WebSocket session if there's an unhandled error. It's something like this:
val handler = CoroutineExceptionHandler { _, exception ->
log.error("Closing WebSocket session due to an unhandled error", exception)
session.close(POLICY_VIOLATION)
}
I was surprised to find that the exception handler doesn't just receive exceptions, but is actually invoked for all unhandled throwables, including subtypes of Error. I'm not sure what I should do with these, since I know from the Java API documentation for Error that "an Error [...] indicates serious problems that a reasonable application should not try to catch".
One particular situation that I ran into recently was an OutOfMemoryError due to the amount of data being handled for a session. The OutOfMemoryError was received by my CoroutineExceptionHandler, meaning it was logged and the WebSocket session was closed, but the application continued running. That makes me uncomfortable, because I know that an OutOfMemoryError can be thrown at any point during code execution and as a result can leave the application in a irrecoverable state.
My first question is this: why does the Kotlin API choose to pass these errors to the CoroutineExceptionHandler for me, the programmer, to handle?
And my second question, following directly from that, is: what is the appropriate way for me to handle it? I can think of at least three options:
Continue to do what I'm doing now, which is to close the WebSocket session where the error was raised and hope that rest of the application can recover. As I said, that makes me uncomfortable, particularly when I read answers like this one, in response to a question about catching OutOfMemoryError in Java, which recommends strongly against trying to recover from such errors.
Re-throw the error, letting it propagate to the thread. That's what I would normally do in any other situation where I encounter an Error in normal (or framework) code, on the basis that it will eventually cause the JVM to crash. In my coroutine scope, though, (as with multithreading in general), that's not an option. Re-throwing the exception just ends up sending it to the thread's UncaughtExceptionHandler, which doesn't do anything with it.
Initiate a full shutdown of the application. Stopping the application feels like the safest thing to do, but I'd like to make sure I fully understand the implications. Is there any mechanism for a coroutine to propagate a fatal error to the rest of the application, or would I need to code that capability myself? Is propagation of 'application-fatal' errors something the Kotlin coroutines API designers have considered, or might consider in a future release? How do other multithreading models typically handle these kinds of errors?
Why does the Kotlin API choose to pass these errors to the CoroutineExceptionHandler for me, the programmer, to handle?
The Kotlin docs on exceptions state:
All exception classes in Kotlin are descendants of the class Throwable.
So it seems the Kotlin documentation uses the term exception for all kinds of Throwable, including Error.
Whether an exception in a coroutine should be propagated is actually a result of choosing the coroutine builder (cf. Exception propagation):
Coroutine builders come in two flavors: propagating exceptions automatically (launch and actor) or exposing them to users (async and produce).
If you receive unhandled exceptions at the WebSocket scope it indicates a non-recoverable problem down the call chain. Recoverable exceptions are expected to be handled at the closest possible invocation level. So it is quite natural that you don't know how to respond at the WebSocket scope and indicates a problem with the code you are invoking.
The coroutine functions then choose the safe path and cancel the parent job (which includes cancelling its child jobs), as stated in Cancellation and exceptions:
If a coroutine encounters an exception other than CancellationException, it cancels its parent with that exception. This behaviour cannot be overridden and is used to provide stable coroutines hierarchies for structured concurrency.
What is the appropriate way for me to handle it?
In any case: Try to log it first (as you do already). Consider to provide as much diagnostic data as feasible (including a stack trace).
Remember that the coroutines library has already cancelled jobs for you. In many cases, this would be just good enough. Don't expect the coroutines library to do more than this (not now, not in a future release). It does not have the knowledge to do better. The application server typically provides a configuration for exception handling, e.g. as in Ktor.
Beyond that, it depends, and may involve heuristics and trade-offs. Don't blindly follow "best practices". You know your application's design and requirements better than others. Some aspects to consider:
For efficient operations, restore impacted services automatically and as quickly and seamlessly as reasonable. Sometimes the easy way (shutting down and restarting everything that might be affected) is good enough.
Evaluate the impact of recovering from an unknown state. Is it just a minor glitch, which is easily noticed or do people's lives depend on the outcome? In case of uncaught exceptions: Is the application designed in a way that resources are released and transactions rolled back? Can dependent systems continue unaffectedly?
If you have control over functions called, you might introduce a separate exception class (hierarchy) for recoverable exceptions (which have only a transitory and non-damaging effect) and treat them differently.
When trying to recover a partially working system, consider a staged approach and handle follow-up failures:
If it is sufficient to shut down your coroutines only, leave it at that. You might even keep the WebSocket session open and send a restart indication message to the client. Consider the chapter on Supervision in the Kotlin coroutines documentation.
If that would be unsafe (or a follow-up error occurs), consider shutting down the thread. This would not be relevant with coroutines dispatched to different threads, but a proper solution for systems without inter-thread coupling.
If that would still be unsafe (or a follow-up error occurs), shut down the entire JVM. It all may depend on the exception's underlying cause.
If your application modifies persistent data, make sure it is crash-proof by design (e.g. via atomic transactions or other automatic recovery strategies).
If a design goal of your entire application is to be crash-proof, consider a crash-only software design instead of (possibly complex) shutdown procedures.
In case of an OutOfMemoryError, if the cause was a singularity (e.g. one giant allocation), recovery could proceed in stages as described above. On the other hand, if the JVM cannot even allocate tiny bits, forcibly terminating the JVM via Runtime.halt() might prevent cascading follow-up errors.

Recomendation on literature about how to struct code on classes, methods, functions and so on

Although I have ten years of programming experience, I feel that I am at an amateur level when deciding on how to struct my code.
I'll give some examples to give a better idea of what I'm talking about.
1 - Compiler
I am writing a compiler for hobby language of my own and I've decided to create a Logger class to handle error messages, warning messages and so on. Then I wasn't sure on how to implement. Should I write something like this
Logger log;
log.error("error message");
log.warn("warn message");
Or should I write something like this?
Logger log;
log.log(Logger::ERROR, "error message");
log.log(Logger::WARN, "warn message");
Or instead of a simple string should I create a LogMessage class?
LogMessage msg;
Logger log;
msg.content("error message");
msg.severity(Logger::ERROR);
msg.file(current_file); // file that produced the log
log.log(msg);
In this particular case of logging, it seems that the official Java API regarding logging implements all these alternatives and some more.
2 - A simple TeX parser
Another project I am working needs to parse a small subset of TeX input. One of the steps of this projects needs to read an input like this:
\chapter{Foo} hello, world \section{Bar}
And split the input into an array of strings like this
["\chapter{Foo}", " hello, world ", "\section{Bar}"]
I implemented this functionality using a simple function, but talking with a friend, he said that he probably would have created a specialized class to handle such split in order to follow the SOLID principle. In this case, he argued that the class would be small and have only a single concern as SOLID advocates and that classes are more versatile than functions.
3 - The compiler again
Almost everyone knows that a compiler is not a trivial project. But in my case, my most troublesome issues were regarding abstractions on how to communicate and pass data among the compilation steps. I've rewritten the compiler from scratch four times by now. Each rewrite I've improved the Lexer and Parser code, but I never passed from the semantic phase because I still haven't found a proper and efficient way to tie together the semantic steps, the parser, the lexer, user-defined types, and symbol tables. All my approaches seem to degenerate on a myriad of cases to handle one by one, the code becomes too much verbose and I get frustrated because in my mind I believe that there is a better and elegant way to code instead of handling case by case.
As an example, consider the following inputs to be processed by the compiler
p->foo[2](2, 3)
p->bar = 2
p->baz[2][3].foobar->foo[2](2, 3)
Those simple inputs cause me nightmares because I must check, for example, if the left side of the -> operator, for instance, is a simple member, a function, an array and so on. And in order to produce error messages, I must coordinate symbol tables, the name of the file where the error is produced and so on. I get lost on how to pass so much information around without producing code that is too much verbose.
Before I came here to ask this question, I really thought about how to not let this question become opinionated, subjective and so on. So I decided to ask for books, articles and so on this subject. I would like recommendations of literature on how to struct a program. How to decide if a given functionality should be implemented as a class, or as a method, or as a function. On how to define abstractions to communicate among layers of the software stack. How to define an API and so on. Maybe some visual methodology to guide the structuring process. Ideally, an algorithm on how to code a complex and big algorithm.

is there a proper way to handle multiple errors/exceptions?

in OO programming, is there some conceptual pattern, ideas, about handling multiple errors?
for example, i have a method that performs some checks and should return an error message for each error found
['name is too short', 'name contains invalid unicode sequences', 'name is too long']
now, should i use an array of exceptions (not thrown exceptions)?
or something like this is better:
class MyExceptionList extends Exception{
public Void addException(Exception e){}
public Array getExceptions(){}
}
any theory behind this argument will be appreciated!
(this isn't a request about a specific programming language, but a pure theoretical one)
thank you in advance
Unfortunately, many languages and frameworks (including C++, Java, and .net) use an exception-handling mechanism which requires the type of an an exception object to simultaneously answer many questions, including:
What happened
What actions need to be taken beyond stack unwinding
At what point should the system be considered to be in a "known" state, at least with regard to the problems indicated by the exception.
Unfortunately, while the answers to those questions are somewhat related, they are in reality far from 100% correlated. Unfortunately, the assumption that the type of an exception will be sufficient to answer all of those questions makes it difficult to deal sensibly with many situations.
If you have control over all the exceptions that can be thrown, it may be helpful to use an exception-handling paradigm where the exception-handling object includes a virtual IsResolved property or method along with a ShouldCatchAs<T> property or method that returns a T if the exception needs to be handled as a T. Such a paradigm would be able to smoothly handle situations where an exception occurs while unwinding the stack from an earlier exception (the existing exception and new one would be wrapped into a composite exception object, whose ShouldCatchAs property would combine those of the original exceptions, and whose IsResolved property should only return true when both of the original exceptions' IsResolved properties do likewise).
I don't know any way to integrate such behavior into the existing frameworks unless one catches and wraps all exceptions that don't fit the paradigm, but perhaps future frameworks can facilitate such things.
From my years of experience, dealing with errors is best done via logging them at all levels, and return true/false from functions, indicating success/fail.
Logging is implementation dependant. It could be to a file, to memory, and you can log messages, unique numbers, whatever, as long as the log will enable you to pinpoint the exact place of the error.
I sometimes use exceptions, in cases where I perform many operations, each one depending on the success of its predecessor. This makes the code cleaner, with no ifs for error checking. Nevertheless, this is not the main thing to care about. The main thing is log the errors, and return success/fail. Success/fail is needed so that you can decide whether to continue the normal way or not (such as not doing the indended operation because the read size may overrun the memory).
Two more important notes:
1) You must construct a super easy API to report (log) your messages, otherwise you will find yourself postponing this crucial thing, eventually not doing it.
2) It's essential for the log or report to be easily viewed and inform you about the problems as they accure. Otherwise you might find yourself not using the error report mechansim at all.
This is a very important subject to me, and I believe it to be one of the most important issues in software engineering. You can read more about it on my website
You shouldn't be throwing Exceptions then.
An Exception is meant for an exceptional case. Errors found on a validation method isn't considered "Exceptional", it's rather obvious that validation errors would occur.
An exceptional situation is when your attempt to connect to a database failed, for example.
You should log all validation errors to an array, and then format it and display it as you like.
Exceptions are not intended for validation, they are intended to be created when something that is different from what was expected happens during the execution. This is why you can't create many exceptions at once, but exceptions can be caused because some other exception happened, this is why they can have a parent exception named case.

What is 'exceptional'? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 12 years ago.
I'm looking for a definition of 'exceptional' in terms of unit testing or OOP principles. Several times on SO when talking about exception throwing, I've seen comments like, "Well, I wouldn't consider getting Foo from Bar to be exceptional." (Is there a trollface emoticon?)
I did some googling and an answer wasn't immediately forthcoming. Are there any good definitions, rules of thumb, or guidelines that are more objective than opinion or preference? If one person says "this is exceptional" and another says "no, it isn't", how does one resolve this dispute?
Edit: Wow, so there are a number of answers already, with comments that disagree, and they all seem to be the opinion of the answerers :P Nobody's referenced a wikipedia page or an article a snippet from a greybeard. The 'meta-answer' I'm taking from this is there is no agreed-upon rule of thumb for when to use exceptions. I feel more confident employing my own, personal, idiosyncratic rules when choosing to throw exceptions.
I disagree with the other answers about something needing to be "exceptional" to warrant an "exception". I say "exceptional" is any time you want to break the normal flow of control in the way you can by throwing an upward-propagating object.
Exceptions are a language feature. They're a means to an end. They aren't magical. Like any other feature, when you use them should be guided by when you need what they can provide, not by what they are called.
It's exceptional if:
It is a failure condition. AND
It happens infrequently and
unexpectedly. AND
There is no better mechanism for
reporting it.
edit
Stealing blatantly from Dan Weinreb's blog entry, which Ken posted about here, I'd like to offer the following summary of what exceptions are about.
The method's contract defines how
(and whether) unusual conditions
(ie. failures) are signaled. If the
method says something is an
exception, it just is. Of course,
this leaves open the question of how
we should design the contract.
Exceptions have the benefit of not
requiring any checking by the
caller, as well as naturally
bubbling up until they are caught by
something able to handle them. They
can also contain significant detail,
user-readable text and stack traces.
These features make them ideal for
failure cases that prevent further
processing but are not predictable
or common, or where explicit
error-handling would be disruptive
to code flow. They are especially
good for errors that "should never
happen" but are catastrophic in
effect (such as a stack overflow).
Flags, error codes, magic values
(NULL, nil, INVALID_HANDLE, etc.)
and other return-based mechanisms do
not commandeer flow, and are
therefore better suited for cases
that are common and best handled
locally, especially those where the
failure can be worked around. As
they operate by convention and not
fiat, you cannot count on them to be
detected and handled, except that an
invalid value may be designed to
cause an exception if actually used
(such as an INVALID_HANDLE being
used to read).
When using exceptions in robust
code, each method should catch
unexpected exceptions and wrap them
inside an exception from the
contract. In other words, if your
method does not promise to throw
NullReferenceException, you need to
catch it and rethrow it inside
something more general or specific.
They're called exceptions, not
surprises!
The general rule of thumb is:
Use exceptions for errors that you anticipate, and that could happen.
Use assertions to deal with errors that could never happen.
IMHO, an exception should be thrown, if the further execution of program would result in fatal error or unpredictable behaviour.
Personally, I think that this kind of discussion is a pure waste of time and that "what is exceptional" is the wrong question to ask.
Exceptions are just another flow control mechanism with certain advantages (flow of control can pass multiple levels up the call stack) and disadvantages (somewhat verbose, behaviour is less localized).
Whether it's the right choice should not be determined by its name. Would we have these discussions if exceptions were simply called "bubbleups" instead?
When someone rips out the power chord, that is exceptional, most of the other situations are expected.
Well, Exceptional programming case is one which deviates the program flow from normal stream and it might be due to:
::A h/w of s/w fault that programmer cannot handle in given situation. Programmer may be not sure what to do in those case and he left it to the user or tool/library which invokes this code.
::Even programmer might not be sure the exact environment in which his code will be used and hence it is better to leave the error handling to the one who uses the code.
So exceptional case with a program might be is to use it uncommon environment or with uncommon interactions.
Again uncommon interactions and unknown environments refers to the designers point of view.
So deviation from Normal is exceptional and again it is based on the point of view and context of the programmer.
Is it too round and round?:D
Exceptions are useful when something has gone wrong that's outside the immediate scope of the problem. They should almost never be caught close to where thrown, since if they can be satisfactorily handled there they can be satisfactorily handled without throwing anything.
One example is C++'s containers, which can throw bad_alloc if they can't get the memory they need. The people who wrote the container have no idea what should happen if the container can't get memory. Perhaps this is an expected thing, and the calling code has alternatives. Perhaps this is recoverable. Perhaps this is fatal, but how should it be logged?
Yes, it's possible to pass back error codes, but will they be used? I see lots of C memory allocations without tests for NULL, and printfs that just discard the return value. Moreover, lots of functions don't have a distinguishable error code, like negative for printf and NULL for memory allocation. Where any return value can be valid, it's necessary to find a way to return an error indication, and that leads to more complication than most programmers are willing to deal with. An exception cannot be ignored, and doesn't require lots of defensive code.
The best discussion of this that I've seen is in Dan Weinreb's blog: What Conditions (Exceptions) are Really About.
It's ostensibly about Common Lisp, whose condition system is like a more flexible form of exceptions, but there's almost no Lisp code and you don't need to be a Common Lisp programmer to follow the concepts.
And another good rule of thumb - never use exceptions to catch conditions that you can catch in code.
For example if you have a method divides 2 variables, don't use an exception to catch divide by zero errors, instead do the necessary checks beforehand.
Bad code example:
float x;
try {
x = a / b;
{
catch (System.DivideByZeoException) {
x = 0;
}
Good code example:
if (b == 0)
return 0;
Exceptions are generally expensive.
I'm not going to get into the holy war of whether exceptions ought to be used as flow control or not, but rather I'm going to focus on what an exceptional event is...
Oracle, in the context of Java, defines an exceptional event this way:
An exception is an event, which occurs
during the execution of a program,
that disrupts the normal flow of the
program's instructions.
Of course, this definition applies to exceptions in general, not just in Java.
The key here is "disrupts the normal flow". In other words, the program fails in such a way that it can't complete its instructions.
A program has a defined range of functionality. When all your program's functionality is accounted for (including handling of invalid input), anything that is left over is an exception and likely a bug.
I believe there are two kinds of exceptions:
Bugs, which are introduced into the program by the programmer.
Uncontrollable situations, like someone else said, pulling the power plug. Of course, the program wouldn't get to throw an exception in this case, but if it could, it would. Other exceptions might be some sort of failure within the OS or network that the program relies on.
For instance: A program ought to handle invalid input from users as part of its normal flow, because users will of course give you invalid input at some point. This isn't a disruption because the program's functionality should be able to parse input and see if it's valid.
However, if a programmer somehow allows null to be passed to a method that isn't supposed to accept null, then that's an exception. The method's behavior is undefined for values of null. While it's a gray area, the reason I don't necessarily consider this invalid input like the above example is because the method has a certain spec, and by coding something into the program that passes a value violating that spec, it's a bug.
Exception should be used for things you can't control within your program. Most of time, this means you are working with external files or an internet/database connection.
For user input, YOU should control it before you compute anything with it.
Of course there is a limit to what you can expect and you should stop before reaching the "armless person exception". We came up with this term when we were programming something with movement detector and one of our friend was over-protecting his code. So we told him: "Yeah so, did you control what happens if an armless person put his hand in front of the detector?". We got a good laugh with it :)
Two main cases:
When calling code has asked you to do something unreasonable.
When outside dependencies have left you with nothing reasonable to do.
In the first case consider a method int IntegerDivide(int dividend, int divisor). Now, we all know we should catch conditions like dividing by zero ourselves. However, if the calling code has asked this method to divide by zero, it's too late - it's not our code that is deciding to divide by zero, it's the calling code. The only reasonable thing to do here is to throw an exception.
In the second case, consider a component that reads a file and returns some sort of computed result, and what it should do when it fails to open the file. If we had access to the user interface, then we should catch this failure and present a useful and informative message to the user. However we don't, as we're writing a component for use by other code closer to the UI. Again, the only thing we can do is throw an exception (and hope that the calling code does the right thing when it comes to informing the user).