Why are there Errors AND Exceptions in Dart and not either Errors OR Exceptions?
Is the reason a historical one oder what?
I can throw an Error, I can throw an Exception. None of them is checked by the Analyzer like in Java (Exception vs. RuntimeException)
From this post, quoting Bob Nystrom:
Error and its subclasses are for programmatic errors. If one of those
occurs, your code is bad and you should fix your code.
Non-Error exception classes are for runtime errors. Sometimes you can
prevent them from being thrown, but often you cannot.
Except in a few special circumstances, idiomatic Dart should throw
Errors, but never catch them. They exists specifically to not be
caught so that they take down the app and alert the programmer to the
location of the bug.
In other words, you should expect (and check for) exceptions (it is intended that you should handle them). If you get an error, then you need to check how you're using the API that's throwing the error - you're probably using it wrong.
If you're writing an API, then you should use the same pattern. Errors are messages to downstream developers about how they are using your API.
Exception
An Exception in Dart should be thrown for regular, expected program flow and is intended to be caught:
An Exception is intended to convey information to the user about a failure, so that the error can be addressed programmatically. It is intended to be caught, and it should contain useful data fields.
Example: TimeoutException
A TimeoutException will be thrown "when a scheduled timeout happens while waiting for an async result", which is expected program flow.
If we have a download task for example and that download task is not finished after our specified timeout time of thirty seconds (which can happen), we want to communicate that to our user, hence, we need to catch the Exception.
Error
An Error in Dart should be thrown for unexpected program flow and should not be caught but addressed by the programmer:
An Error object represents a program failure that the programmer should have avoided.
Example: AssertionError
An AssertionError is thrown "when an assert statement fails", i.e. it should never happen because we assert that it should not.
If we see such an error, it means that we should change our code and we should definitely not catch the error.
In practice you can catch Errors, but you should not. There is a linter rule to help enforce that.
The fact that Dart allows it can still be useful, e.g. when testing assertions or other errors.
See this answer for a complete example scenario.
Exceptions are considered conditions that you can plan ahead for and catch.
Errors are conditions that you don't expect or plan for.
For more detailed ans
Thanks to Chris and from here
Exceptions should be used when there is a problem that is expected. A common one is any type of I/O operation (like network traffic), where the socket closes early, and trying to write data to that socket fails.
Errors occur when there is a problem that was not expected. Things like null pointers (you expected this variable to not be null), running our of memory, etc... When you try to use the API in a wrong way or stuffs like that.
For the most part you, as an app developer, will always use exceptions. Errors tend to be reserved for unexpected and fatal problems.
Related
I've been following along with some tutorials and have built an app that I'd like to publish, but I'm unsure how to deal with error handling.
Tutorials teach you about things like do-catch blocks but whenever they deal with the case where an error is thrown, they just log the error to console, which is obviously unhelpful in a production environment.
Moreover, some examples of the do-catch blocks appear to have little use. As an example, I'm using Realm Database as a core part of my app, and I'm told the way to initialise it is like so in the AppDelegate:
do {
_ = try Realm()
} catch {
// TODO: - Handle Exception
}
But in this case, since realm is a core part of my app, I wouldn't even mind if it crashed the app, because if it doesn't init properly it's going to crash later anyway.
There are obvious cases when I should just display an error to the user (e.g. If you're trying to connect to an API but there is no wifi), or where a default value could be provided, but I don't know what to do here.
There's no single good approach to handling errors, since how an error should be handled completely depends on the exact situation.
In general, however, there are some guidelines on error handling:
Use do-catch blocks on throwable functions unless you have a very
good reason to do so
Avoid runtime errors at all costs and don't throw fatal errors. Even if your app encounters an error that cannot be properly handled (the results of a throwable function is absolutely needed for your app to function), don't let your app crash due to a runtime error, rather let the user know that there's something wrong. A crashing application sends a very bad message to your users, while failing gracefully after encountering an error doesn't seem as bad.
In a catch block, try to solve the error without
letting the user know that there was an error if the error is
recoverable (for instance, you can use a default value instead of the
value you expected from the throwable function)
If the error can't be
handled, let the user know that there was an error (such as they
don't have internet connection when making a network request or a
network request failed for any other reason) and try to give them an
alternative approach (i.e. try later when you have internet
connection)
Only use try! and similar forced methods (force unwrapping, etc.) if you are absolutely sure that the function won't actually throw an error (for instance Realm.init() can only throw an error on the very first call to it in an app's lifecycle, so after the first instantiation of Realm, you can safely do try! Realm()) or if the error represent a programmer error (such as a file not being in the right place, which is needed for the application), but make sure you actually correct such errors in the development phase
I've set Application.OnException to a custom exception handler so that I can log crashes and give an option to exit. However, I'm now finding that this runs even on exceptions that I've already handled, for instance, exceptions that come up when validating number inputs. Is there a way to have the custom exception handler only run on unhandled exceptions?
Edit: it turns out that I get the expected behavior when I run outside the debugger. Maybe it's just a debugger thing. I do not find the Delphi debugger's interaction with exceptions to be intuitive, to say the least.
If behavior changes inside and outside the debugger, then it's not really your program that's telling you about exceptions. I've written about this phenomenon on my Web site:
Why do I continue getting error messages even after I have written an exception handler?
An excerpt:
In its default settings, the Delphi IDE notifies you whenever an exception occurs in your program ... . What’s important to realize is that at that point, none of your program’s exception-handling code has run yet. It’s all Delphi itself; its special status as a debugger allows it to get first notification of any exception in your program, even before your program knows about it.
After you dismiss Delphi’s message box, execution will be paused at the best line of your source code Delphi could find to represent the source of the exception. Press the “Run” button to have your program resume. Control will pass to the next finally or except
block. Before you resume your program, you may use the various debugging tools at your disposal. You can inspect the values of any variables in scope, and you can even modify their values.
So, how do you notify Delphi that you've already handled an exception? You don't — because your program hasn't handled it yet. And why can't the debugger detect whether your program is going to handle an exception? Because in order to do that, it needs to execute your program further. Detecting the lack of an exception handler is like solving the halting problem. The only way to determine whether an exception is going to be handled is to let the program run and then see whether the exception gets handled. But by that point, it's too late to do any debugging, so the debugger has no choice but to pause your program when it first detects an exception and then let you figure out what to do from there.
My article goes on to describe some ways you can avoid having the debugger catch certain exceptions, summarized here:
Use advanced breakpoints to temporarily disable breaking on exceptions for certain regions of the code.
Configure the debugger to ignore certain classes of exceptions (and their descendants).
Tell the debugger not to notify you about any exceptions.
Disable integrated debugging altogether.
There's another options that I didn't include in my article:
Change your program such that the exception doesn't get raised in the first place.
You say you're validating numeric input. That sounds to me like you're doing something like calling StrToInt and then catching the EConvertError exception when the input isn't a valid integer. That's an expensive way of validating input. Instead of that, use TryStrToInt, which will tell you whether the conversion succeeded, or StrToIntDef, which will silently return a default value instead of raising an exception. Another option is plain old Val, which tries to convert a string, and if it fails, it tells you which position in the string caused the failure. Val is particularly useful if you want to consume as many characters as possible for the conversion and then resume parsing at the next non-numeric character.
Quoting from the documentation (Delphi 7) on TApplication.OnException
"Use OnException to change the default behavior that occurs when an exception is not
handled by application code."
So: Only unhandled exception will be available in the OnException event handler. What you are experiencing is probably the Delphi IDE breaking on the exception. This is (at least in Delphi 7) configurable.
In Delphi 7 you can configure it by clicking on the Tools->Debugger Options menu. Then select the "Language Exceptions" an un-ckech the "Stop on Delphi exceptions" checkbox. It might however be different in other delphi versions.
An alternative might be to not use Application.OnException. But to simply catch all exceptions in your "main" function. That way you can catch all exceptions you have not cached before, log the exception, and then crash.
Application.OnException should only fire for unhandled exceptions. Re-raising an exception in a try-except block will cause the exception to be handled by Application.OnException. For input validation that raises an exception, you could display a message to the user and then re-raise the exception only if you want it recorded into the error log.
I've set Application.OnException to a custom exception handler so that I can log crashes and give an option to exit. However, I'm now finding that this runs even on exceptions that I've already handled, for instance, exceptions that come up when validating number inputs. Is there a way to have the custom exception handler only run on unhandled exceptions?
Edit: it turns out that I get the expected behavior when I run outside the debugger. Maybe it's just a debugger thing. I do not find the Delphi debugger's interaction with exceptions to be intuitive, to say the least.
If behavior changes inside and outside the debugger, then it's not really your program that's telling you about exceptions. I've written about this phenomenon on my Web site:
Why do I continue getting error messages even after I have written an exception handler?
An excerpt:
In its default settings, the Delphi IDE notifies you whenever an exception occurs in your program ... . What’s important to realize is that at that point, none of your program’s exception-handling code has run yet. It’s all Delphi itself; its special status as a debugger allows it to get first notification of any exception in your program, even before your program knows about it.
After you dismiss Delphi’s message box, execution will be paused at the best line of your source code Delphi could find to represent the source of the exception. Press the “Run” button to have your program resume. Control will pass to the next finally or except
block. Before you resume your program, you may use the various debugging tools at your disposal. You can inspect the values of any variables in scope, and you can even modify their values.
So, how do you notify Delphi that you've already handled an exception? You don't — because your program hasn't handled it yet. And why can't the debugger detect whether your program is going to handle an exception? Because in order to do that, it needs to execute your program further. Detecting the lack of an exception handler is like solving the halting problem. The only way to determine whether an exception is going to be handled is to let the program run and then see whether the exception gets handled. But by that point, it's too late to do any debugging, so the debugger has no choice but to pause your program when it first detects an exception and then let you figure out what to do from there.
My article goes on to describe some ways you can avoid having the debugger catch certain exceptions, summarized here:
Use advanced breakpoints to temporarily disable breaking on exceptions for certain regions of the code.
Configure the debugger to ignore certain classes of exceptions (and their descendants).
Tell the debugger not to notify you about any exceptions.
Disable integrated debugging altogether.
There's another options that I didn't include in my article:
Change your program such that the exception doesn't get raised in the first place.
You say you're validating numeric input. That sounds to me like you're doing something like calling StrToInt and then catching the EConvertError exception when the input isn't a valid integer. That's an expensive way of validating input. Instead of that, use TryStrToInt, which will tell you whether the conversion succeeded, or StrToIntDef, which will silently return a default value instead of raising an exception. Another option is plain old Val, which tries to convert a string, and if it fails, it tells you which position in the string caused the failure. Val is particularly useful if you want to consume as many characters as possible for the conversion and then resume parsing at the next non-numeric character.
Quoting from the documentation (Delphi 7) on TApplication.OnException
"Use OnException to change the default behavior that occurs when an exception is not
handled by application code."
So: Only unhandled exception will be available in the OnException event handler. What you are experiencing is probably the Delphi IDE breaking on the exception. This is (at least in Delphi 7) configurable.
In Delphi 7 you can configure it by clicking on the Tools->Debugger Options menu. Then select the "Language Exceptions" an un-ckech the "Stop on Delphi exceptions" checkbox. It might however be different in other delphi versions.
An alternative might be to not use Application.OnException. But to simply catch all exceptions in your "main" function. That way you can catch all exceptions you have not cached before, log the exception, and then crash.
Application.OnException should only fire for unhandled exceptions. Re-raising an exception in a try-except block will cause the exception to be handled by Application.OnException. For input validation that raises an exception, you could display a message to the user and then re-raise the exception only if you want it recorded into the error log.
Am new to the iOS development. While looking into one of the App I work on, with exception breakpoint enabled in xcode. I see so many repetitive exceptions been raised.
But till now, we never realised this, as iOS was excusing those exceptions. The main exception was happening in our service layer, where, in an XML parsing, one of the element mentioned as key was missing. since so many back end requests are fired, for every XML response, and for multiple items inside it, this exception is thrown.
Now that our app is published, will this impact the device's stability? We are planning to fix thee kind of issues. But now, Will these be logged into Apple's diagnostic information. Just curious to know these. Can someone shed some light over it?
In Objective-C, Exceptions are used to signal fatal errors, that is programmer errors and "unexpected" and unrecoverable runtime errors. In Objective-C, Exceptions are a debugging and testing aid, not a construct to control program flow or to regain control after an error.
Usually, an application in a release state shouldn't throw exceptions. If it happens anyway, the only correct course of action is to terminate the program as soon as possible. In general, the Objective-C system frameworks are not exception safe. This means, after an exception has been thrown the application's state will be corrupt. If your program continues, even worse things may happen.
There are only a few, always undocumented harmless cases where exceptions will be thrown and caught by system libraries without leaving the program in an unstable condition.
See also https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Exceptions/Exceptions.html
I've set Application.OnException to a custom exception handler so that I can log crashes and give an option to exit. However, I'm now finding that this runs even on exceptions that I've already handled, for instance, exceptions that come up when validating number inputs. Is there a way to have the custom exception handler only run on unhandled exceptions?
Edit: it turns out that I get the expected behavior when I run outside the debugger. Maybe it's just a debugger thing. I do not find the Delphi debugger's interaction with exceptions to be intuitive, to say the least.
If behavior changes inside and outside the debugger, then it's not really your program that's telling you about exceptions. I've written about this phenomenon on my Web site:
Why do I continue getting error messages even after I have written an exception handler?
An excerpt:
In its default settings, the Delphi IDE notifies you whenever an exception occurs in your program ... . What’s important to realize is that at that point, none of your program’s exception-handling code has run yet. It’s all Delphi itself; its special status as a debugger allows it to get first notification of any exception in your program, even before your program knows about it.
After you dismiss Delphi’s message box, execution will be paused at the best line of your source code Delphi could find to represent the source of the exception. Press the “Run” button to have your program resume. Control will pass to the next finally or except
block. Before you resume your program, you may use the various debugging tools at your disposal. You can inspect the values of any variables in scope, and you can even modify their values.
So, how do you notify Delphi that you've already handled an exception? You don't — because your program hasn't handled it yet. And why can't the debugger detect whether your program is going to handle an exception? Because in order to do that, it needs to execute your program further. Detecting the lack of an exception handler is like solving the halting problem. The only way to determine whether an exception is going to be handled is to let the program run and then see whether the exception gets handled. But by that point, it's too late to do any debugging, so the debugger has no choice but to pause your program when it first detects an exception and then let you figure out what to do from there.
My article goes on to describe some ways you can avoid having the debugger catch certain exceptions, summarized here:
Use advanced breakpoints to temporarily disable breaking on exceptions for certain regions of the code.
Configure the debugger to ignore certain classes of exceptions (and their descendants).
Tell the debugger not to notify you about any exceptions.
Disable integrated debugging altogether.
There's another options that I didn't include in my article:
Change your program such that the exception doesn't get raised in the first place.
You say you're validating numeric input. That sounds to me like you're doing something like calling StrToInt and then catching the EConvertError exception when the input isn't a valid integer. That's an expensive way of validating input. Instead of that, use TryStrToInt, which will tell you whether the conversion succeeded, or StrToIntDef, which will silently return a default value instead of raising an exception. Another option is plain old Val, which tries to convert a string, and if it fails, it tells you which position in the string caused the failure. Val is particularly useful if you want to consume as many characters as possible for the conversion and then resume parsing at the next non-numeric character.
Quoting from the documentation (Delphi 7) on TApplication.OnException
"Use OnException to change the default behavior that occurs when an exception is not
handled by application code."
So: Only unhandled exception will be available in the OnException event handler. What you are experiencing is probably the Delphi IDE breaking on the exception. This is (at least in Delphi 7) configurable.
In Delphi 7 you can configure it by clicking on the Tools->Debugger Options menu. Then select the "Language Exceptions" an un-ckech the "Stop on Delphi exceptions" checkbox. It might however be different in other delphi versions.
An alternative might be to not use Application.OnException. But to simply catch all exceptions in your "main" function. That way you can catch all exceptions you have not cached before, log the exception, and then crash.
Application.OnException should only fire for unhandled exceptions. Re-raising an exception in a try-except block will cause the exception to be handled by Application.OnException. For input validation that raises an exception, you could display a message to the user and then re-raise the exception only if you want it recorded into the error log.