Language design (Exceptions): Why `try`? [closed] - exception

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
In the languages where I've seen exceptions (C++, Java, Javascript, Python, PHP, ...), I always see try, or something similar, to mark the scope of a catch. I wonder if it's necessary. What are the design issues with NOT having try blocks?
For example, take this:
try{
try{
do_something_dangerous0();
}catch (SomeProblem p){
handle(p);
}
try{
do_something_dangerous1();
}catch (SomeProblem p){
handle(p);
}
}catch (SomeOtherProblem p){
handle(p);
}
I imagine this as an alternative.
do_something_dangerous0();
catch (SomeProblem p){
handle(p);
}
do_something_dangerous1();
catch (SomeProblem p){
//catches from only the second unless the first also threw
handle(p);
}
catch (SomeOtherProblem p){
//catches from either, because no other block up there would
handle(p);
}
If you want to avoid a block catching "too much", you can make a new scope:
do_something_dangerous2();
{
do_something_dangerous3();
catch (SomeProblem p){
//does not catch from do_something_dangerous2()
//because if that throws, it won't reach in here
handle(p);
}
}
catch (SomeProblem p){
handle(p);
}
catch (SomeOtherProblem p){
handle(p);
}
(My answer for why this won't work for languages like C++ and Java, at least, is posted as an answer below, but I don't have an answer for dynamic languages.)

It wouldn't work for languages which require variable declarations, at least.
Any statement in the try block may fail to fully execute, including declarations and initializations of variables. In languages with block scoping, especially languages that require variable declarations like C++, Objective C, and Java, the catch block does not share the scope of the try block, so it is not allowed to access the try's local variables. The try-less system would break scoping rules.
For example, this is valid C++ code.
try{
int x = some_func();
int y = some_other_func();
}catch(SomeException){
//...
}
If this were converted to,
int x = some_func();
int y = some_other_func();
catch(SomeException){
//...
}
then, under the brace scoping rules, x and y are in-scope for the catch block, even though they might not be declared/initialized yet.
You can change the scoping rules so that the catch won't see those variable declarations, but that's a major complication of a very simple and pervasive rule to save on about seven characters (try{\n }\n). You can make it so that you can't do variable declarations immediately outside the scope of a catch, but then you can't do much without something like try blocks anyway. You can require all variables in a scope to be declared before running anything that can throw (similar to old C), but that takes away some freedom in structuring code and makes it harder to read.

Related

What's the best func signature for a function that fetches an object and might not find it? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
This is a very similar question to this, but focusing Go implementation.
Let's say you have a function that fetches an object using some ID. The function might not find that object.
Something like:
func FindUserByID(id int) *User {
....
}
How should you handle a situation where the user is not found?
There's a number of patterns and solutions to follow. Some are common, some are favorable in specific languages.
I need to choose a solution that is suitable in Go (golang), and so I want to go through all the options and get some feedback on what's the best approach here.
Go have some limitations and some features that can be helpful with this issue.
Option 1:
The obvious solution is to have the "Find" function return nil, in case the object wasn't found. As many know, returning nil is unfavorable and forces the caller do check for nil, making "nil" the magic value for "not found".
func FindUserByID(id int) *User {
...
if /*user not found*/ {
return nil
}
...
}
It works. And it's simple.
Option 2:
Returning an exception - "NotFound".
Goland does not support exceptions. The only alternative is to have the function to return an error, and check the error in the caller code:
func FindUserByID(id int) (*User, error) {
...
return errors.New("NotFound")
}
func Foo() {
User, err := FindUserByID(123)
if err.Error() == "NotFound" {
...
}
...
}
Since Go does not support exceptions, the above is a code smell, relying on error string.
Option 3:
Separate to 2 different functions: one will check if the object exists, and the other will return it.
func FindUserByID(id int) *User {
....
}
func IsExist(id int) bool {
...
}
The problem with it is:
Checking if the object exists in many cases means also fetching it. So we pay penalty for doing the same operation twice (assume no caching available).
The call to "IsExist" can return true, but "Find" can fail if the object was removed by the time it was called. In high concurrency applications it can happen very often. Which again forces checking nil value from "Find".
Option 4:
Change the name of "Find" to suggest it may return nil. This is common in .Net and the name can be "TryFindByID".
But many people hate this pattern and I haven't seen it anywhere else. And anyhow it's still makes the nil value the magic "not exist" mark.
Option 5:
In some languages (java, c++) there's the "Optional" pattern. This makes a clear signature and helps the caller understand she needs to call "isEmpty()" first.
Unfortunately this is not available in Go. There are some projects in github (like https://github.com/markphelps/optional) but since Go is limited and does not support returning generic types without casting, it means another compilation step is required to creat an Optional struct for out object, and use that in the function signature.
func FindUserByID(id int) OptionalUser {
....
}
func Foo() {
optionalUser := FindUserByID(123)
if optionalUser.IsEmpty() {
...
}
...
}
But it depends on 3rd parties and adds compilation complexity. It doubles the amount of structs that follow this pattern.
Option 6:
Go support returning multiple values in a function. So the "Find" function can also return a bool value if the object exists.
func FindUserByID(id int) (*User, bool) {
...
if /*user not found*/ {
return nil, false
}
...
}
This seems to be a favorable approach in Go. For example, casting in Go also returns a bool value saying if the operation was successful.
I wonder what's the best approach and to get some feedback on the above options.
Edited: Changed the User to be pointer (better serves the example)
This question is fundamentally opinion-based, and as such I hesitate to answer. But there's enough going on here that I think it warrants an answer, not just comments.
You've given 6 options, but really there are only three. Most of your 6 options fall under my first category. At the bottom, I'll give a specific critique of each of your proposals.
Return the user, and a boolean indicating whether it was found.
In this case, my preference is to always return a literal boolean (but emphasis: this is my opinion, not an objective fact):
func FindUserByID(id string) (*User, bool)
Of your 6 options, this is the most obvious to any casual reader of the code. It leaves no guesswork about whether a nil value might be returned, or if you have to look up some complex API to do a 2-phase lookup, etc.
Return the user, and an error, possibly including a 'Not Found' status.
If you have the option of other error states (such as timeouts, database errors, malformed input, etc), then a simple boolean is not sufficient, and you must return an error (or panic, more on that in a moment). In such a case, my preference (again: my opinion), is to use the error to convey not-found as well:
func FindUserByID(id string) (*User, error)
In this case, you can use a sentinel error value that is easy to check from your caller:
var ErrNotFound = errors.New("not found")
func FindUserByID(id string) (*User, error) {
/* couldn't find the user, so... */
return nil, ErrNotFound
}
and elsewhere in your code...
user, err := database.FindUserByID("1234")
if err == database.ErrNotFound {
/* behave accordingly */
}
Generally speaking, though, sentinel errors are not best practice. It's usually better convey the error type through an interface, but this is beyond the scope of this question. Further reading here if you're interested.
Return the user, or panic.
And the final option is to panic (i.e. "throw an exception" in other languages). But this should be avoided in practically all cases, and it's absolutely the wrong approach for this sort of function. I just mention it here for completeness. DON'T DO THIS
func FindUserByID(id string) *User {
/* Couldn't find the user so... */
panic("Can't find the user!")
}
Here's my specific critique of your 6 options (again: my opinion).
Option 1: Return nil when not found.
This is non-intuitive. My advice is to only do this when the zero-value (nil in your case) is valid in its own right. It probably isn't for a user. It might be for something like a count.
Option 2: Return an exception
Your example actually only returns an error, not an exception (panic). Returning an error is a perfectly valid option, but do not resort to checking error strings. See my discussion above.
Option 3: One function to check, one to retrieve
This is non-intuitive, and racy. It's not obvious how to use this cumbersome API, so I would avoid it. It's also racy, because there's no guarantee that between the check and the retrieve, that a new user hasn't been created, or an existing one deleted.
Option 4: Change the name to suggest it returns nil
This would be a slight improvement over option #1, but not idiomatic Go. There are better alternatives.
Option 5: IsEmpty() method
This is just a cumbersome way to return a boolean. Prefer an actual boolean.
Option 6: Return a boolean
This is a valid option, seen throughout the standard library. It's appropriate if no other error condition is possible. See above commentary.

Are exceptions fundamental, or can they be replaced with conditions?

I am attempting to understand from where exception conditions derive. My question is at the end, but I will present an example that might make it clearer.
Take this Java code, for example. It has the path to a file and set-up a File object. If the path is null, an exception is thrown.
String path = getPathName();
try {
File file = new File(path);
} catch (NullPointerException e) {
// ...
}
This is hardly an exceptional circumstance, though, and if we could modify it in such a way that this might be preferrable:
String path = getPathName();
if (path == null) {
path = DEFAULT_PATH;
}
File file = new File(path); # we've removed the need for an exception
But moving further, we run into a new exception when we try and make the File readable.
try {
file.setReadable(true);
} catch (SecurityException e) {
// ...
}
We can skirt around this issue by checking two conditions:
SecurityManager sm = System.getSecurityManager();
if (sm != null && sm.checkWrite(path)) {
// modify the SecurityManager
} else {
file.setReadable(true);
}
With this example in mind, on to my question...
If we move down the stack, going from Java to the OS, etc., is it possible to replace all exception handling code with if-else branches? Or is there some root cause of exceptions (hardware?) that means they are "baked" into programming?
If we move down the stack, going from Java to the OS, etc., is it possible to replace all exception handling code with if-else branches?
Yes. This is how it used to be done, and still is in languages without exceptions. Exceptions are used because they are easier in a number of senses. The primary advantages are that cases not anticipated by the programmer can be aggregated in a general handler; and that information about the exceptional condition does not need to be explicitly preserved in every single function until it is properly handled.
Or is there some root cause of exceptions (hardware?) that means they are "baked" into programming?
Also yes. In general, unexpected hardware conditions need to be handled in some way, unless you are comfortable with undefined behaviour in such cases.
If all the methods in a program returned a pointer/reference to some kind of "exception" object (for other return values, pass in a pointer or reference to a caller-allocated storage location), and if every call to every method which might directly or indirectly want to throw an exception were bracketed with something like:
ret = callFunction( ...parameters...);
if (ret != NULL)
return AddToExceptionStacktrace(ret, ...info about this call site... );
then there would be no need for any other form of exception handling (note that if the type supports scoped variables, the "return" statement would have to insert code to clean them up before it actually returns to the caller).
Unfortunately, that's a lot of extra code. This approach would be workable in a language which had only "checked" exceptions (meaning a method can neither throw exceptions nor pass them through unless it is declared as doing so), but adding that overhead to every function which might directly or indirectly call a function which throws an exception would be very expensive. Exception-handling mechanisms generally eliminate 99% of the extra overhead in the no-exceptions case, and the expense of increasing the overhead in the "exception" case.

Jump out of "try-catch"?

Is there a language with a keyword to jump out of try-catch block?
For example, there is a walkaround in Ruby:
lambda {
begin
p 0
break
p 1
rescue
p 2
end
}.call
p 3
It's also (I believe) possible in Javascript.
But I want a way without anonymous function (to avoid indentation) – like if break or continue were possible.
I know, that C/C++/C# languages allow using goto.
Do languages with another approach exist?
You could always just throw a known exception which you catch but do nothing with. In c#
try {
if(true)
throw new GetOutException();
}
catch(GetOutException e) {
}
catch(Exception e) {
// Do something here
}
Using continuations, you can jump out of any part in the code. For instance, with call-with-current-continuation in Scheme. This example from wikipedia illustrates the basic concept:
(define (f return)
(return 2)
3)
(display (f (lambda (x) x))) ; displays 3
(display (call-with-current-continuation f)) ; displays 2
In general, a continuation can be used to escape from any point in the execution of a procedure (they're not limited to try/catch blocks), no matter how deeply nested it is - in that regard, it's a more general construct than an Exception or a goto, as both of those constructs can be implemented in terms of continuations.
At first, continuations are not an easy-to-grasp concept, but with practice they can be very useful, see this paper detailing the many possible applications of continuations.
So basically it sounds like you're asking for a goto equivalent to skip the execution of particular parts of your code. Something like:
foo();
if (!bar) {
goto end;
}
baz();
end:
print "ended";
I won't go into pros and cons of gotos, but they're not available in a number of languages for various reasons. You can virtually always formulate your code like below for the same effect though:
foo();
if (bar) {
baz();
}
print "ended";
This obviously also works when you're actually using exceptions:
try {
foo();
if (bar) {
baz();
}
} catch (Exception e) {
help();
}
print "ended";
It has the same effect of skipping the execution of a particular branch of code under certain circumstances and is the standard way to do it. I cannot really imagine a situation where breaking out of a try..catch or using an equivalent goto would offer any advantage.

What is the point of finally in a try catch/except finally statement

I have used try-catch/except-finally variants in many languages for years, today someone asked me what is the point of finally and I couldn't answer.
Basically why would you put a statement in finally instead of just putting it after the whole try-catch block? Or in other words is there a difference between the following blocks of code:
try{ //a}
catch {//b}
finally {//c}
try{//a}
catch{//b}
//c
EDIT:
PEOPLE, I know what finally does, I have been using it for ages, but my question is in the above example putting //c in finally seems redundant, doesn't it?
The purpose of a finally block is to ensure that code gets run in three circumstances which would not very cleanly be handled using "catch" blocks alone:
If code within the try block exits via fallthrough or return
If code within a catch block either rethrows the caught exception, or--accidentally or intentionally--ends up throwing a new one.
If the code within the try block encounters an exception for which the try has no catch.
One could copy the finally code before every return or throw, and wrap catch blocks within their own try/catch to allow for the possibility of an accidental exception occurring, but it's far easier to forgo all that and simply use a finally block.
BTW, one thing I wish language designers would include would be an exception argument to the finally block, to deal with the case where one needs to clean up after an exception but still wants it to percolate up the call stack (e.g. one could wrap the code for a constructor in such a construct, and Dispose the object under construction if the constructor was going to exit with an exception).
Finally block is executed even if an exception thrown in the try block. Therefore, for instance if you opened a stream before, you may want to close that stream either an exception is thrown or not. Finally block is useful for such an issue.
finally is a syntactic sugar to allow DRY principle in try-catch pattern. Exception is usually thrown if the library code has not enough information to handle some state and wants the client code to solve it. If you don't have library-client code separation, you can handle everything by if instead of try.
Let's see a standard situation without finally:
void myFunction() {
var r = allocateResources();
r.doSomething();
if(somethingBadHappens) {
freeResources(r);
throw new Exception(CODE42);
}
r.doSomethingMore();
freeResources(r);
}
In the snippet above, you repeat freeResources(): this can be multiple statements which you need to repeat. This smells and finally block is the solution for clean code:
void myFunction() {
var r = allocateResources();
try {
r.doSomething();
if(somethingBadHappens) throw new Exception(CODE42);
r.doSomethingMore();
}
finally {
freeResources(r);
}
happyFunction();
}
Let's realize three levels of abstraction:
A1 is the library code providing allocateResources() function
A2 is our code providing myFunction, consuming A1
A3 is some client code consuming myFunction in try-catch block:
function A3code() {
try {
myFunction();
doSomething();
}
catch(Exception e) {
// no hanging resources here
Console.WriteLine(e);
}
}
Now let's see what can happen:
if allocateResources() throws in A1, we don't know how to handle it in A2 (A2 code can be run in Console-free environment), so we delagate the situation to A3 without adding any further code. If Exception is thrown here, the finally block is not executed, since finally is bound to try which was not entered.
if somethingBadHappens in try block, the stack unwinds to A3 where the situation is handled BUT before it finally block is executed, so we don't need to repeat it if no exceptions happen.
before finally we can add catch block and try to resolve some potential exceptions from A1 which may appear in calling r.doSomething methods. Usually we want to handle exceptions as soon as possible to make the client code (A3) more comfortable for client coders.
happyFunction() is executed only if nothing throws in myFunction() (inside or outside of try block).
As #supercat points out, the finally block is executed also if try block exits via return. I suggest you avoid this bad habit and have only one return in every function (maybe some early exists at the very beginning of functions). The reasons for single-return functions are:
The code is more readable: you look at the end and see WHAT the function returns. In multiple returns you must find all return occurences, inspect all the ifs, think about when the ifs are satisfied and only then you know what the function returns.
The code can be optimized by compilers, see copy elision.
The reason for multiple returns is avoiding many nested ifs, but there are other techniques to solve it. Exceptions are exception in this rule.
Learn by example
let v = 0;
function f() {
try {
v = 1;
return 2;
} finally {
v = 3;
return 4;
}
v = 5;
return 6;
}
const r = f();
console.log(r, v);
following prints "3, 4"
Finally make sure your code is executed even if you get an exception.
The finally block is useful for cleaning up any resources allocated in the try block as well as running any code that must execute even if there is an exception
http://msdn.microsoft.com/en-us/library/zwc8s4fz(v=vs.80).aspx

Returning values vs returning error codes?

This is a general programming question, not pertaining to any specific language.
A new programmer typically will write a method that calculates some value, then returns the value:
public Integer doSomething()
{
// Calculate something
return something;
}
public void main()
{
Integer myValue = doSomething();
}
But when an exception occurs during the calculation of something, what is the best way to handle the exception, especially when giving the user feedback? If you do a try/catch of the calculation of something and if an exception is caught, what do you return? Nothing was calculated, so do you return null? And once you return it (whatever it may be), do you need to do another try/catch in the parent method that checks to see if a valid value was returned? And if not, then make sure the user is given some feedback?
I have heard arguments on both sides of the table about never returning values at all, but instead setting calculated values as pointers or global variables and instead returning only error codes from methods, and then (in the parent method) simply handling the error codes accordingly.
Is there a best practice or approach to this? Are there any good resources that one could access to learn more about the best way to handle this?
UPDATE for Clarification
Consider the following code:
public void main()
{
int myValue = getMyValue();
MyUIObject whatever = new MyUIObject();
whatever.displayValue(myValue); // Display the value in the UI or something
}
public Integer getMyValue()
{
try
{
// Calculate some value
} catch (exception e) {
// ??
}
return value;
}
I call the method to get some int value, then I return it. Back in main(), I do something with the value, like show it in the Log in this case. Usually I would display the value in the UI for the user.
Anyways, if an exception is caught in getMyValue(), so does value get returned but it's null? What happens in main() then? Do I have to test if it's a valid value in main() as well?
I need the program to handle the error accordingly and continue. Someone below suggested displaying the appropriate information in the UI from within the getMyValue() method. I see two potential issues:
It seems like I would be mixing the business logic with (in this case) the logic for the UI.
I would have to pass a reference of the MyUIObject to the getMyValue() or something so I could access it from within the function. In the above simple example that is no big deal, but if there is a BUNCH of UI elements that need to be updated or changed based off of what happens in getMyValue(), passing them all might be a bit much...
I've read a bunch about the fundamentals of all of this but I can't seem to find a straight answer for the above situation. I appreciate any help or insight.
I think you do not quite understand exceptions.
If you throw an exception, you do not return from the function normally:
public Integer doSomething()
{
throw new my_exception();
// The following code does NOT get run
return something;
}
public void main()
{
Integer myValue = doSomething();
}
The main advantages of exceptions are:
You can write your code as though everything is succeeding, which is usually clearer
Exceptions are hard to ignore. If an exception is unhandled, typically an obvious and loud error will be given, with a stack trace. This contrasts with error codes, where it is much easier to ignore the error handling than not.
I recommend this post by Eric Lippert, which discusses exceptions and when it is and is not appropriate to handle them.
UPDATE (in response to comment):
You can absolutely handle an exception and continue, you do this by catching the exception.
eg:
try
{
// Perform calculation
}
catch (ExceptionType ex)
{
// A problem of type 'ExceptionType' occurred - you can do whatever you
// want here.
// You could log it to a list, which will be later shown to the user,
// you could set a flag to pop up a dialog box later, etc
}
// The code here will still get run even if ExceptionType was thrown inside
// the try {} block, because we caught and handled that exception.
The nice thing about this is that you know what kind of thing went wrong (from the exception type), as well as details (by looking into the information in ex), so you
hopefully have the information you need to do the right thing.
UPDATE 2 in response to your edit:
You should handle the exception at the layer where you are able to respond in the way you want. For your example, you are correct, you should not be catching the exception so deep down in the code, since you don't have access to the UI, etc and you thus can't really do anything useful.
How about this version of your example code:
public void main()
{
int myValue = -1; // some default value
String error = null; // or however you do it in Java (:
try
{
getMyValue();
}
catch (exception e)
{
error = "Error calculating value. Check your input or something.";
}
if (error != null)
{
// Display the error message to the user, or maybe add it to a list of many
// errors to be displayed later, etc.
// Note: if we are just adding to a list, we could do that in the catch().
}
// Run this code regardless of error - will display default value
// if there was error.
// Alternatively, we could wrap this in an 'else' if we don't want to
// display anything in the case of an error.
MyUIObject whatever = new MyUIObject();
whatever.displayValue(myValue); // Display the value in the UI or something
}
public Integer getMyValue()
{
// Calculate some value, don't worry about exceptions since we can't
// do anything useful at this level.
return value;
}
Exceptions is a property of object oriented languages (OOL). If you use OOL, you should prefer exceptions. It is much better than to return error codes. You can find nice examples how the error-codes approach generates a vastly longer source code than exceptions based code. For example if you want to read a file and do something with it and save in a different format. You can do it in C without exceptions, but your code will be full of if(error)... statements, maybe you will try to use some goto statements, maybe some macros to make it shorter. But also absolutely nontransparent and hard to understand. Also you can often simply forget to test the return value so you don't see the error and program goes on. That's not good. On the other hand if you write in OOL and use exceptions, your source code focuses on "what to do when there is no error", and error handling is in a different place. Just one single error handling code for many possible file errors. The source code is shorter, more clear etc.
I personally would never try to return error codes in object oriented languages. One exception is C++ where the system of exceptions have some limitations.
You wrote:
I have heard arguments on both sides of the table about never returning values at all, but instead setting calculated values as pointers or global variables and instead returning only error codes from methods, and then (in the parent method) simply handling the error codes accordingly.
[EDIT]
Actually, excetion can be seen as error code, which comes along with the relative message, and you as the programmer should know where your exception must be caught, handled and eventually display to the user. As long as you let the exception to propagate (going down in the stack of called functions) no return values are used, so you don't have to care about handling related missed values. Good exception handling is a quite tough issue.
As jwd replied, I don't see the point to raise an exception in a method and then handle the excpetion in the same method just to return an error value. To clarify:
public Integer doSomething(){
try{
throw new my_exception();}
catch{ return err_value;}
}
is pointless.