March 23, 2017
On Thursday, 23 March 2017 at 19:47:29 UTC, Walter Bright wrote:
> Over time I've found that standardized Exception types seem to become less and less useful over just using "Exception" with an appropriate message.

I'm of the firm belief that exceptions should NEVER have a string message - that's a code smell. If you do it right, all the info can be determined automatically by the exception type and passed arguments and *that* is what gets printed to string.

D can do a pretty amazing job at this too with templates btw.
March 23, 2017
On Thursday, March 23, 2017 21:34:45 Jacob Carlborg via Digitalmars-d wrote:
> On 2017-03-23 20:47, Walter Bright wrote:
> > Thanks for expressing this better than I could have. Over time I've found that standardized Exception types seem to become less and less useful over just using "Exception" with an appropriate message.
>
> A plain Exception is completely useless, it can just as well be an assertion instead. Because it's not possible to extract any information from the exception (except for trying to parse the message which is a bad idea) resulting in not being able to act on a thrown exception. Which then results in it being pointless to catch the exception in the first place.
>
> I think it's a bad design that it's possible created instances of Exception, it should either be an abstract class or an interface.

There are plenty of cases where all you care about is that something went wrong when calling a function and aren't going to do anything special depending on what went wrong. You just handle it and move on. In other cases, any exception of any kind means that you're done and exiting your program, which _is_ similar to an assertion, but the key difference is that assertions are for catching programming errors, not for reporting stuff like bad user input or that the file you're trying to operate on doesn't exist anymore. Regardless, having a generic exception type is useful.

Now, there are plenty of cases where specific exception types should be used - particularly if you want to be able to have your program respond differently depending on what went wrong - but for those to be effective, they need to actually be specific, whereas most any exception type that one might consider adding to std.exception is generic and thus in pretty much the same boat as Exception. So, I see no point in general exceptions like IOException. In those cases, you might as well just use Exception.

I frequently create specific exception types for libraries that I write or for pieces of libraries, because then you know where the exception came from (which can affect how you handle it), and if it's a specific type related to specific functionality within a library, then catching it specifically can really inform what exception handling code should be doing.

That being said, there are plenty of cases where I'm not sure that there's much point in creating a new exception type. If it's not something that someone is going to handle differently depending on its type, and all you really care about reporting is that something went wrong, Exception is perfect for that. And in cases like D scripts, it would be overkill to be forced to create your own exception types, so it would really annoying if you couldn't create Exceptions.

- Jonathan M Davis

March 23, 2017
On Thursday, March 23, 2017 12:47:29 Walter Bright via Digitalmars-d wrote:
> On 3/23/2017 9:44 AM, Jonathan M Davis via Digitalmars-d wrote:
[...]
> Thanks for expressing this better than I could have. Over time I've found that standardized Exception types seem to become less and less useful over just using "Exception" with an appropriate message.

I used to think that standard exceptions made sense - I may have even argued as much in a discussion or two in this newsgroup years ago - but over time, I've come to the conclusion that they would be detrimental. I find that in most cases, either all I care about is that something went wrong (in which case, Exception is enough), or I need to know fairly specifically what went wrong so that I can respond differently based on what went wrong, and in those cases, a standard exception wouldn't be any different from Exception. It simply wouldn't provide the information that I need. It can make sense when additional information is provided (like we do with ErrnoException or SocketOSException), but that's often primarily to aid in construction of the exception type rather than really having any effect on how you handle it.

What I'm increasingly on the fence about is exceptions that are specific to modules or libraries but don't really provide any additional information over what you get with Exception. We have several instances of this in Phobos (e.g. DateTimeException and URIException), and I've often done it with libraries where the entire library or a section of the library has a specific exception type. That helps indicate where the exception originates from (though stack traces obviously hepl with that), and it allows you to catch exceptions based on which library or section of a library is mad at you (which is sometimes useful), but often, it's not much different from just using Exception. To an extent, it depends on what functionality is getting its own exception, and usually, the more narrow that is, the more useful the exception type is, but ultimately, I don't know what the best approach is with such exception types.

Where specific exceptions definitely make sense is stuff like FileException or SocketOSException, which provide additional information as to what went wrong - or GetOptException, where knowing what piece of functionality is mad at you is exactly what you need to know. Exception types like IOException or InvalidArgumentException simply don't tell you enough to do reliably respond to them based on what they're telling you - _especially_ if every library under the sun could be throwing them at you. At least if they were specific to a particular library, then you'd know what section of code is screaming at you, and that combined with the general type of exception might be enough to do something useful, even if the type of the exception is overly generic.

- Jonathan M Davis

March 23, 2017
On Thursday, 23 March 2017 at 16:44:51 UTC, Jonathan M Davis wrote:
> I honestly think that trying to standardize exceptions is a bad idea. They _should_ be specific to specific libraries or applications, otherwise they're not much different from just throwing Exception.

With a single hierarchy it becomes difficult, but with a multiple inheritance design it makes sense to have some standards. For instance whether the exceptional situation is permanent or warrants a retry.


March 23, 2017
On Thursday, 23 March 2017 at 21:31:28 UTC, Ola Fosheim Grøstad wrote:
> On Thursday, 23 March 2017 at 16:44:51 UTC, Jonathan M Davis wrote:
> With a single hierarchy it becomes difficult, but with a multiple inheritance design it makes sense to have some standards. For instance whether the exceptional situation is permanent or warrants a retry.

Strong hierarchy is one of the reasons, that makes exception types less reusable. You want to use a class, but it inherits another class, that name contradicts what you want to say, throwing the exception.

For instance, you want to say, that parsing goes wrong. And somebody already made ParseException, but it is derived from FileException. And your parsing doesn't relate to files or file system at all.

On the other hand, the exception interfaces would be perceived like tags at a blog article. Unfortunately, I don't know D good enough. Is there the catch statements, that are active only for such exceptions, that is match multiple types (implements all enumerated interfaces) - if we want to catch a very specific case.
March 23, 2017
On Thursday, 23 March 2017 at 22:12:23 UTC, Георгий wrote:
> Is there the catch statements, that are active only for such exceptions, that is match multiple types (implements all enumerated interfaces) - if we want to catch a very specific case.

https://dpaste.dzfl.pl/246264774900
No, it can't be catched by interface at all.
March 23, 2017
On 3/23/2017 1:34 PM, Jacob Carlborg wrote:
> A plain Exception is completely useless, it can just as well be an assertion
> instead. Because it's not possible to extract any information from the exception
> (except for trying to parse the message which is a bad idea) resulting in not
> being able to act on a thrown exception. Which then results in it being
> pointless to catch the exception in the first place.

It's a compelling point, and is the reason why there are many different exception types in Phobos.

But in my experience, if an error happens and it is local enough to be dealt with specifically, it is checked for directly without needing to go through an exception. If one is far enough removed from the source of the error that one is relying on exceptions, pretty much all one can do is the binary "it worked" or "it did not work". The "why it did not work" message is then logged or sent to the user, that is the only recovery necessary.

The fine grained Exception types is one of those things that sounds compelling but just doesn't seem to pay off in practice.
March 23, 2017
On 3/23/2017 1:45 PM, Adam D. Ruppe wrote:
> I'm of the firm belief that exceptions should NEVER have a string message -
> that's a code smell. If you do it right, all the info can be determined
> automatically by the exception type and passed arguments and *that* is what gets
> printed to string.

The string is what gets printed to the user like:

   "your password has to have at least one upper case character in it"

In general, such is not deducible from the type/arguments.

Exceptions are not for debugging the code (that's what Errors are for), Exceptions are for informing the user that he did it wrong.

March 23, 2017
On Thu, Mar 23, 2017 at 05:28:16PM -0700, Walter Bright via Digitalmars-d wrote:
> On 3/23/2017 1:45 PM, Adam D. Ruppe wrote:
> > I'm of the firm belief that exceptions should NEVER have a string message - that's a code smell. If you do it right, all the info can be determined automatically by the exception type and passed arguments and *that* is what gets printed to string.
> 
> The string is what gets printed to the user like:
> 
>    "your password has to have at least one upper case character in it"
> 
> In general, such is not deducible from the type/arguments.
[...]

You *could*, in theory, create very fine-grained exception types like:

	class PasswordInsufficientCharSetException {
		string category; // like "uppercase letters"
		int quorum;
	}

	class PasswordMinLengthException {
		int minLength;
	}

	try { checkPassword(pw); }
	catch(PasswordInsufficientCharSetException e) {
		writeln("Your password must have at least %d characters from the category %s",
			e.quorum, e.category);
	}
	catch(PasswordMinLengthException e) {
		writeln("Your password must be at least %d characters long", e.minLength);
	}
	catch( /* other fine-grained types */ ) { ... }

The problem with this, though, is that every such fine-grained exception type becomes part of the tight coupling between the throwing code and the catching code, to the point that you end up essentially forcing the catching code (usually user code if the exception is thrown from a library) to implement what you could have already implemented in a much easier way in the throwing code instead.

Essentially, having exceptions of this level of detail forces the catching code to be dependent on the implementation details of the throwing code (it has to know which set of exceptions can be thrown, and it has to know the details of the exceptions it'd like to catch, what each detail means, and what to do with it), which breaks encapsulation and is what I'd call the *real* code smell.

It's a different story, of course, if the library provides a getErrorMessage(Exception e) function that hides these details away from the catching code's eyes. But in that case you might as well just include the error message in the original exception in the first place.


T

-- 
People tell me I'm stubborn, but I refuse to accept it!
March 23, 2017
On Thursday, March 23, 2017 22:41:39 Георгий via Digitalmars-d wrote:
> On Thursday, 23 March 2017 at 22:12:23 UTC, Георгий wrote:
> > Is there the catch statements, that are active only for such exceptions, that is match multiple types (implements all enumerated interfaces) - if we want to catch a very specific case.
>
> https://dpaste.dzfl.pl/246264774900
> No, it can't be catched by interface at all.

catch can only catch Throwable or any class derived from Throwable (normally though, you'd only catch Exception or classes derived from it). As such, you cannot catch an interface. Now, you _can_ catch a base type and then attempt to cast it to various interfaces if you want to, but that would be more or less the same as catching an exception type with an error code and having the catch block's behavior depend on the error code. These restrictions are the result of trying to avoid the C++ mess of being able to catch stuff like string or int.

- Jonathan M Davis