-3

Why would I ever throw exceptions in code? (except for one specific scenario where I am developing a class library which the consumers of it, will not want / be able to change).

To be more specific, is there any reason to do this:

class EmailSender
{
   public void SendEmail(string recipient, string subject, string content)
   {
       if (string.IsNullOrEmpty(recipient))
       {
           throw new ArgumentNullException("exception text...");
       }

       // Send the email
   }

}

Instead of this:

class EmailSender
{
   public bool SendEmail(string recipient, string subject, string content)
   {
       bool result = false;

       try
       {
           if (string.IsNullOrEmpty(recipient))
           {
              logger.Error("Error text...");
           }
           else
           {
              // Send the email
              result = true;
           }
       }
       catch (Exception ex)
       {
           logger.Error(ex);
       }

       return result;
   }
}

Take into account that this class is in-house code and not something I am going to ship as a DLL or an open source project.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Uri Abramson
  • 111
  • 4
  • This is not a duplicate because my question here is not whether or not I should REDUCE the use of exception throw. I am asking why would I EVER use exception throw... Please remove duplicate suggestion. – Uri Abramson Dec 01 '15 at 17:30
  • 1
    see also: [Exceptions: Why throw early? Why catch late?](http://programmers.stackexchange.com/questions/231057/exceptions-why-throw-early-why-catch-late) – gnat Dec 01 '15 at 17:34
  • It doesn't answer my simple question of "Why ever throw exceptions when you can use a result value". – Uri Abramson Dec 01 '15 at 17:45
  • For the same reasons that you would ever want to throw exceptions. What do you mean exactly? Whether it's framework code or not doesn't matter; the reasons still apply. – Robert Harvey Dec 01 '15 at 17:47
  • 1
    Anyway, I have a good reason. If you swallow all of your exceptions in a logger, the only way you're *ever* going to know something bad happened is to examine the log. – Robert Harvey Dec 01 '15 at 17:49
  • @Robert Harvey Well, if you throw exceptions inside a function the consumer wouldbt know whether or not he should catch anything but if you return a result value, the consumer knows that the return value can either be true or false and act accordingly. Isnt it cleaner than a global exception handler GOTO? – Uri Abramson Dec 01 '15 at 17:53
  • 5
    Perhaps. But a true or false doesn't tell you *anything*, except that the method succeeded or failed. An exception gives you an error message, a stack trace, and line numbers to the code that failed. – Robert Harvey Dec 01 '15 at 17:56
  • @RobertHarvey Why would a consumer of SendEmail care why it failed? For the sake of the example, lets assume that the consumer cares about it and that different reasons for failure would have effect for flow of code. Wouldn't it be better to return an enum of EmailSendResult with Success, FailureReason1, FailureReason2, etc... and then the consumer would know in advance all the options that can occur because it would make him check the result value of SendEmail. What do you think? – Uri Abramson Dec 01 '15 at 18:40
  • @UriAbramson an error message can be more descriptive than an enum, which in this case is standing in for a string. For example, what would you prefer? An enum of CONNECTION_FAILED or the string "Could not connect to host 127.0.0.1" (but with a real IP address)? An exception can contain an arbitrary amount of state which can help a bit more than a simple enum. Another great example is Java's [SQLException](https://docs.oracle.com/javase/8/docs/api/java/sql/SQLException.html) class which can even include vendor-specific error codes for the underlying database engine. –  Dec 01 '15 at 18:43
  • Would you parse the error string in the calling function? I think not.. what you care about is ONLY what affects the flow of your code.. You can check the exact error message in the logs. Usually it answers all scenarios... It might happen that you would need to parse the string of the exception to extract a specific value but that's a whole different story I guess. – Uri Abramson Dec 01 '15 at 18:46
  • @UriAbramson: That's an argument for swallowing exceptions in SendMail, not an argument for eliminating exception handling altogether. – Robert Harvey Dec 01 '15 at 18:48
  • Its not getting swallowed because its written to logs and I'm getting an email alert about it immediately. What I am saying is that if you have strict separation of concerns, the calling code will only need to know what affects his flow. If the calling code needed to know more, like the exception content for example, I would return it in the result object because its a part of what the function was built to do and the consumer should know just by reading its signature all of his options. – Uri Abramson Dec 01 '15 at 18:51
  • That's an argument for *checked exceptions.* – Robert Harvey Dec 01 '15 at 19:44
  • 2
    *Please stop adding meta commentary to your question!* If you want to do that, you can put it here, in the comments. – Robert Harvey Dec 01 '15 at 19:44
  • What do you mean argument for checked exceptions could you please explaim? – Uri Abramson Dec 01 '15 at 19:48
  • Check out Java to find out more about checked exceptions. Though you should probably know that most Java developers find them more trouble than they're worth. – Robert Harvey Dec 01 '15 at 20:11

2 Answers2

6

Are you asking why not always handle the error inside the same method the error is detected?

It is rarely the case that you can handle an error at the same level as where the problem is detected, it is only possible because you example is contrived. For example, what if the "send the mail" logic contains multiple method calls:

VerifyAdresses(recipient);
ConnectToSmtpServer();
PostMessage();

What if an error is detected in VerifyAdresses or ConnectToSmtpServer? If the method just logs the error and continues happily (as in your example), the PostMessage will be execute in any case, probably with a much more severe error as result.

You need to handle errors at the level where it is possible to gracefully recover. For example you can handle error in the mailing logic by not sending the mail. But you cannot gracefully handle an error locally inside VerifyAdresses() if that error prevents the whole operation of sending an mail. You need to be able to drop back up the call stack (possibly multiple steps) to the level where the error can sensibly be handled.


Edit: OK, you are really asking why not use C-style success/error result codes instead of exceptions. This discussion have been beaten to death, but suffice to say that the framework have made the choice for you. Result codes consistently used may in theory be as good as exceptions (if much more tedious and error prone), but since the framework already uses exceptions, it would be incredibly confusing and a waste of resources to use both exceptions and result codes in the same code base.

JacquesB
  • 57,310
  • 21
  • 127
  • 176
  • Not always, only in public functions. In your example, you are basically trusting on VerifyAccess to assert your code. This is GOTO programming style... Why not go with the same pattern and do this instead: If (VerifyAccess() && ConnectToSMTPServer()) { PostMessage(); } ? – Uri Abramson Dec 01 '15 at 18:40
  • @UriAbramson: Bacause VerifyAccess() or ConnectToSMTPServer() might in turn call other functions, and an error could be detected multiple levels down. – JacquesB Dec 01 '15 at 18:45
  • Well, going by the same pattern again, they would only call public functions which return a result object themselves so it would still work. This way you will have a SINGLE POINT OF ENTRY + EXIT throughout your entire code base and will not have to deal with exception GOTO unexpected logic. – Uri Abramson Dec 01 '15 at 18:47
  • Every public function knows what to check for arguments and will return success or failure (only if these have a meaning for calling code). – Uri Abramson Dec 01 '15 at 18:48
  • 3
    So are you are really asking why not use result codes (C style) to indicate errors, rather then exception? – JacquesB Dec 01 '15 at 18:48
  • Usually the caller would not need to know the specific failure reason unless it has affect on his code flow - which makes it an integral part of what the function was meant to do (and thus, makes sense in a way to add it as a result code) but as I said, that's pretty unusual when following this patten. Lets even take your own code for example... Why would somebody calling SendEmail need to tell whether it failed during SMPT authorization or during a server Timeout? (except for sending it to log file) – Uri Abramson Dec 01 '15 at 18:53
  • Buddy, you are not getting my point... usually if you have good separation of concerns you only need a boolean result. Only true/false. in less than 1% of cases you would need to create result codes which is not the best practice but its worth it over the exceptions ASSEMLY goto techniuque. You still haven't answered whether consumers of SendEmail care about where exactly it failed. – Uri Abramson Dec 01 '15 at 19:05
  • @UriAbramson: I consider a boolean sucess/error value as a kind of result code. In any case, exceptions are no more "goto"-style than the use of result-codes. Exceptions only travel up the call stack, which is the same you do with returning result codes upwards multiple levels. Assembly-style goto is something completely different since it allows you to jump to arbitrary locations in the program. I don't see how this is even comparable. – JacquesB Dec 01 '15 at 19:10
  • But then you don't have a single point of exit for each function, I hope we don't have to go into why this is bad... – Uri Abramson Dec 01 '15 at 19:22
  • 1
    @UriAbramson: The discussion of exceptions versus result codes have been done many times already - see the sidebar. If you have a more specific question, you should update and clarify your question. – JacquesB Dec 02 '15 at 07:31
0

Software generally consists of layers of functionality. (i.e. the application layer, the persistence layer, the network layer, the database layer, etc.)

A "library" is a layer of functionality which has been distanced from your code by having been moved into a separate binary file, but this is just a technicality, the point is that it is just another layer of functionality.

A layer of functionality generally communicates errors to the layer above by throwing exceptions.

So, if all of the software that you are writing lives in a single layer as thin as a crispy pizza dough, then yes, I suppose there may be no need for you to ever throw an exception.

But if you ever do anything non-trivial in your career, then you will of course work simultaneously at different layers, and therefore you will have a need to throw an exception in one layer, to be caught (or not) by a layer above.

Mike Nakis
  • 32,003
  • 7
  • 76
  • 111
  • Thanks for the answer... by saying "A layer of functionality generally communicates errors to the layer above by throwing exceptions." you are just making a statement without explaining why - which was my question exactly. And another thing - difference between Library and In-House code is that you cannot change a library because the code is inaccessible so in that case, you have to wrap and throw the exceptions in order to make them loggable (at the least) for calling code. – Uri Abramson Dec 01 '15 at 19:00
  • `you are just making a statement without explaining why - which was my question exactly.` Oh, it did not occur to me that we were going to debate the usefulness of exceptions all over again. In this case, this question was rightfully closed as a duplicate. I thought you were asking something more subtle, like why throw exceptions in application code. – Mike Nakis Dec 02 '15 at 00:55
  • What I mean is that you have other ways of comminicating through layers. – Uri Abramson Dec 02 '15 at 06:23
  • But... I thought that we are not talking about communication in general, we are talking about communicating the occurrence of *errors*. – Mike Nakis Dec 02 '15 at 10:56