2

lvl is an enum class.

switch(lvl)
{
case LogLevel::Trace:
    return "Trace";
case LogLevel::Debug:
    return "Debug";
case LogLevel::Info:
    return "Info";
case LogLevel::Warning:
    return "Warning";
case LogLevel::Error:
    return "Error";
case LogLevel::Fatal:
    return "Fatal";
default:
    assert(0 && "Unhandled LogLevel in LevelToStr"); return "???";      // This one?
    throw std::invalid_argument( "Unhandled LogLevel in LevelToStr" );  // or this one?
}

The consensus is the default should be there, but the opinions in the related question are divided on what it should be doing. Crash the whole thing? Crash the current thread? Try to handle the exception gracefully?

The sides present some arguments in the comments but the discussion isn't quite conclusive.

Could someone present a comprehensive answer which one should be used, or in which conditions?

Community
  • 1
  • 1
SF.
  • 13,549
  • 14
  • 71
  • 107
  • So, concluding by the votes and close-votes: Nobody Really Knows. – SF. May 09 '16 at 10:04
  • _"So, concluding by the votes and close-votes ..."_ No, your conclusion is wrong. It's your question that is _too broad_, _primarily opinion based_ in first place. – πάντα ῥεῖ May 09 '16 at 10:10
  • @πάνταῥεῖ: Precisely two options. Can you really write a book on which one to choose depending on your situation? And is it merely a matter of personal tastes and nobody can present a compelling logical argument where which one is better? – SF. May 09 '16 at 10:15
  • @SF. `Can you really write a book on which one to choose depending on your situation?` Are you telling me there aren't entire books dedicated to exceptions? I would be surprised if that were the case. – uh oh somebody needs a pupper May 09 '16 at 10:31
  • @user6292850: Exceptions are easily a subject that could span a book. Inheritance and structuring, design patterns based on exceptions, graceful recovery after an exception, internal mechanisms of stack unrolling etc. This here though is a binary choice. The nearest subject that is a binary choice broad enough that you can write a book on it is "Does God exist?". – SF. May 09 '16 at 11:02
  • @SF Well, as _@Richard_ correctly stated: _"It completely depends on the requirements of your system."_ – πάντα ῥεῖ May 09 '16 at 11:10
  • 2
    @πάνταῥεῖ: Yes, it does. But HOW does it depend? What factors should I consider when making the choice? Is StackOverflow all about pointing typos in students' programs nowadays, and questions about learning how to make meaningful program design choices became off-topic? Each of the two options comes with a range of advantages and disadvantages. Considering them against the project requirements, I can make the choice. But I don't have a nearly good image enough of what advantages and disadvantages each has. – SF. May 09 '16 at 11:19
  • @SF Not sure, but maybe your question fits better for Programmers SE. – πάντα ῥεῖ May 09 '16 at 11:50
  • @πάνταῥεῖ: With this I can agree. – SF. May 09 '16 at 12:47

1 Answers1

2

It completely depends on the requirements of your system.

I would actually argue that it's better not to use default: in this case. If you leave it out, you'll get a useful warning if you missed a case at compile time. If you compile with -Werror then your program will fail to compile until you've fixed the warning.

void handle_something(LogLevel lvl)
{
    switch(lvl)
    {
    case LogLevel::Trace:
        return "Trace";
    case LogLevel::Debug:
        return "Debug";
    case LogLevel::Info:
        return "Info";
    case LogLevel::Warning:
        return "Warning";
    case LogLevel::Error:
        return "Error";
    case LogLevel::Fatal:
        return "Fatal";
    // note: no default case - better not to suppress the warning
    }

    // handle the default case here

    // ok, so now we have a warning at compilation time if we miss one (good!)
    // next question: can the program possibly continue if this value is wrong?
   // if yes...
   return some_default_action();

   // ... do we want debug builds to stop here? Often yes since
   // ... this condition is symptomatic of a more serious problem
   // ... somewhere else

   std::assert(!"invalid log level");

   // ...if no, do we want to provide information as to why
   // ... which can be nested into an exception chain and presented
   // ... to someone for diagnosis?

   throw std::logic_error("invalid error level: " + std::to_string(static_cast<int>(lvl));

  // ... or are we in some mission-critical system which must abort and
  // ... restart the application when it encounters a logic error?

  store_error_in_syslog(fatal, "invalid log level");
  std::abort();
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142