I suppose this scratches a vast topic, but what is the best approach in handling program work-flow other than the ideal variant when everything gets done the best way.
Let's be a bit more specific:
a class has a method, that method operates on its parameters and returns result.
e.g.:
public Map<Object,OurObject> doTheWork(OtherObject oo);
One possible outcome that I ruled out was returning null if something went other way, but the ideal.
Is there a correct way ("silver bullet", or so called "best practice") of handling that situation?
I see three other outcomes:
1 - the method returns EMPTY_MAP;
2 - the method has checked exceptions;
3 - throwing a RuntimeException;
If there is no generally correct answer to that question - what are the conditions that should be considered?
Regarding the principles of design by contract (in brief, the method's responsibility is to take care of the output, assuming input parameters are correct) - is it correct for the method to throw any exception or it is better to return empty result, though correct in structure (e.g. not null)
Returning null is like setting a trap for someone. (In cases like HashMaps we've been trained to look out for nulls, so going along with precedent is ok.) The user has to know to look out for the null, and they have to code an alternative path to handle that case (which sounds a lot like handling an exception), or risk an NPE (in which case an exception gets thrown anyway, just a less informative one, at a distance from the place where the original problem occurred, so information about what went wrong will be missing).
Returning an empty map makes it unclear whether anything went wrong or not. It isn't hurtful like returning null, but it is totally ambiguous. If somehow returning the map data is purely a best-effort thing and the user doesn't really need to know, this could be ok. (But this is pretty rare.)
If there is anything you expect the user to be able to do about the exception, throwing a checked exception may be appropriate.
If there is nothing the user can do about the exception, or if the exception would only occur due to a programming error, or due to something that should be caught during testing, then an argument can be made for using an unchecked exception. There is a lot of room for disagreement about what should be checked and what should be unchecked.
Which option would be most beneficial to the callee? If all you need to know is an empty map or null is returned, then that is fine. If you need more information, then an exception would be a better choice.
As for what type of exception, if the callee really needs to do something in order to recover, then a checked exception is appropriate. However, an unchecked exception is likely cleaner.
As for returning null or an empty map, it depends on what the callee is going to do with it. If you expect the callee to take that map and pass it around elsewhere, then an empty map is a better choice.
If something in you method breaks because of erroneous input the user needs to know. Therefore, an exception is the best way to go. Returning empty or null data could potentially make the user think that nothing is wrong and that is definitely not what you want.
I'll bet that there's plenty of good answers for this in stackoverflow. Before I search for them:
Exceptions are thrown in exceptional situations only - they are not used for normal control flow.
Checked exceptions are thrown when the caller should be able to recover from the exception
Unchecked exceptions are thrown when the caller probably should not recover from the exception e.g. exceptions thrown due to programming errors.
An empty collection should be returned if it is a normal state. Especially when the result is a collection, the return value should not be null. If the the return value is null, then it should be clearly documented. If there's need for more complicated analysis of the return state, you might be better of with a appropriately modeled result class.
It all depends on how big of a problem it is if doTheWork.
If the problem is so large that the application might need to shutdown then throw a RuntimeException.
If the callee might be able to recover from the problem then a CheckedException is common.
If an empty Map has no meaning then it can be used as a return, but you have to be careful that an empty Map is not a valid value to return in a successful case.
If you do return just a null, I would suggest making a note in the Javadoc about the return value.
The best pattern in many cases is the try/do pattern, where many routines have two variations, e.g. TryGetValue() and GetValue(). They are designed to handle three scenarios:
The object was obtained successfully
The value couldn't be obtained, for a reason the caller might reasonably anticipate, and the system state is what the caller would expect given such a failure.
The value couldn't be obtained, for some reason the caller probably isn't anticipating, or else the system state is corrupted in a way the caller won't expect.
The idea behind the try/do pattern is that there are times when a caller will be prepared to handle a failure, but there are other times where the only thing the caller could do in case of failure would be to throw an exception. In the latter case, it would be better for the method which failed to throw the exception rather than requiring the caller to do it.
Related
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.
I recently heard of the anti-if campaign and the efforts of some OOP gurus to write code without ifs, but using polymorphism instead. I just don't get how that should work, I mean, how it should ALWAYS work.
I already use polymorphism (didn't know about anti-if campaign), so, I was curious about "bad" and "dangerous" ifs and I went to see my code (Java/Swift/Objective-C) to see where I use if most, and it looks like these are the cases:
Check of null values. This is the most common situation where I ever use ifs. If a value could possibly be null, I have to manage it in a correct way. To use it, instead I have to check that it's not null. I don't see how polymorphism could compensate this without ifs.
Check for right values. I'll do an example here: Let's suppose that I have a login/signup application. I want to check that user did actually write a password, or that it's longer than 5 characters. How could it possibly be done without if/switches? Again, it's not about the type but about the value.
(optional) check errors. Optional because it's similar to point 2 about right values. If I get either a value or an error (passed as params) in a block/closure, how can I handle the error object if I just can't check if it's null or isn't?
If you know more about this campaign, please answer in scope of that. I'm asking this to understand their purposes and how effectively it could be done what they say.
So, I know not using ifs at all may not be the smartest idea ever, but just asking if and how it could effectively be done in an OOP program.
You'll never completely get rid of ifs, but you can minimize them.
Regarding null value checks, a method that would otherwise return a null value can return a Null Object instead, an object that doesn't represent a real value but implements some of the same behavior as a real value. Its callers can just call methods on the Null Object instead of checking to see if it's null. There is probably still an if inside the method, but there don't need to be any in the callers.
Regarding correct value checks, the best path is to prevent an object from being instantiated with incorrect attributes. All users of the object can then be confident that they don't have to inspect the object's attributes to use it. Similarly, if an object can have an attribute that is valid or invalid, it can hide that from its users by providing higher-level methods that do the right thing for the current attribute value. Again, there is still a if inside the object, but there don't need to be any in the callers.
Regarding error checks, there are a couple of strategies that are better than returning a possibly null error value that the caller might forget to check. One is raising an exception. Another is to return an object of a type that can hold either a result or an error and provides type-safe, if-free ways to operate on either result when appropriate, like Java's Optional or Haskell's Maybe.
Note also that case statements are just concatenated ifs (in fact I'd have written the code on the campaign's home page with a switch rather than if/else if), and there are also patterns which replace case with polymorphism, such as the Strategy pattern.
This is a great question and is something that's asked at every OO bootcamp I've been a part of. To begin with, we need to understand why code with a lot of ifs is 'bad' or 'dangerous':
they increase the cyclomatic complexity of the code, making it hard to follow/understand.
they make tests more complicated to write. Ensuring that you test each branch flow in the method under test becomes increasingly more difficult with each conditional and makes test setup cumbersome.
they could be a sign that your code has not been broken into small enough methods
they could be a sign that your methods have not been encapsulated well
However, there is one important thing to remember - ifs cannot(and should not) be eliminated from the code completely. But, we can generally abstract them away using techniques like polymorphism, extracting small behaviours, and encapsulating these behaviours into the appropriate classes.
Now that we know some of the reasons why we should avoid ifs, let's tackle your questions:
Checking for null values: The Null object pattern helps you eliminate null checks from your code(polymorphism FTW). Instead of returning null, you return a Special Case NullObject representation of the expected object. This NullObject has the same interfaces as your actual object and you can safely call any of the object's methods without worrying about a null pointer exception being thrown.
Checking for correctness of values: There are a lot of ways to do this. For example, you could create a separate ValidationRule class for each of your validations and then chain calls to them together when you want to validate your object. Notice that the ifs still remain, but they get abstracted away into the individual ValidationRule implementations. Look up the Command pattern and the Chain Of Responsibility pattern for ideas.
It's better to use if to check the null instead of raising an exception. Also in common cases checking for null helps us to prevent operations with non-initialized variables.
Using switch plus SOLID. Other thinks inherited from this.
I hope there is a clear answer to this question.
Is it preferable to extend a custom exception with additional properties, like an item ID or something similar, to allow the exception to be analysed by the receiving client?
The alternative would be to have all the valuable information hidden in the message string. Or to replace the exception by a complex return value with the actual result and the additional context information, which would have been in the exception's properties otherwise.
Thanks for your advice!
It really depends on the scenario. Usually if that's an actual exception (something that stops the method being executed) I would use the first option of extending the exception class.
The string option sounds bad, no matter what the scenario is.
The complex return object sounds good to me when we talk about things like responses (for example - HttpResponse) where you have different layers of problems that can happen (is the exception thrown due to no communication? Maybe credentials error? Or an actual logic exception on the server side?).
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.
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).