February 19, 2012
On 2/18/12 6:40 PM, H. S. Teoh wrote:
> One word: internationalization. Then toString() falls flat on its face.

No. I happen to have some expertise in the area as I've participated to two large and heavily internationalized systems. i18n has everything to do with string tables and formatting templates and emphatically nothing to do with exception hierarchies. The only possible link is that exceptions should provide the necessary hooks.

Andrei

February 19, 2012
On Saturday, February 18, 2012 20:30:45 Andrei Alexandrescu wrote:
> On 2/18/12 6:40 PM, H. S. Teoh wrote:
> > One word: internationalization. Then toString() falls flat on its face.
> 
> No. I happen to have some expertise in the area as I've participated to two large and heavily internationalized systems. i18n has everything to do with string tables and formatting templates and emphatically nothing to do with exception hierarchies. The only possible link is that exceptions should provide the necessary hooks.

They do in that if you want to print a message because of that exception, you need to print something in the correct language, and that won't work with toString unless the exception type has built-in internationalization of some kind - regardless of what that internationalization mechanism might be.

Regardless, it's going to generally be better to generate an application- specific error message than just print out whatever Exception outputs with toString (internationalized or otherwise). And you can't do that if all you have to work with is toString. To do that, you need actual data on what went wrong, which requires additional member variables, which means using a specific exception type.

- Jonathan M Davis
February 19, 2012
On 2/18/12 7:17 PM, H. S. Teoh wrote:
> On Sat, Feb 18, 2012 at 04:28:25PM -0800, Jonathan M Davis wrote:
> [...]
>> C++ is a horrible example of how exceptions should be done, so if
>> you're basing what you want off of that, then that makes me think that
>> you should be better familiar with how other, more recent languages
>> use them (though maybe you're quite familiar with how C# and/or Java
>> use Exceptions, I don't know).  From using Java, I think that how it
>> handles exceptions in general is _far_ superior to how they're
>> frequently dealt with in C++ (though that does tend to depend on who's
>> doing the developing, since you _can_ have a decent exception
>> hierarchy in C++).
> [...]
>
> The basic problem with C++ exceptions is that it allows you to throw
> literally *anything*.

I agree that that was a design mistake, but it's easy to opt out the unnecessary part. All C++ applications I've worked with define exception hierarchies. In fact at Facebook we have a lint rule that prohibits throwing arbitrary stuff.

Andrei
February 19, 2012
On Saturday, February 18, 2012 20:28:32 Andrei Alexandrescu wrote:
> On 2/18/12 6:36 PM, H. S. Teoh wrote:
> > Note also, that an elaborated exception hierarchy lets you attach additional specific information that might be useful in error recovery. For example, FileException may have a field containing the filename that caused the error, so that if the program is processing a list of filenames, it knows which one went wrong. You would not want such information in Exception, because it only applies to FileException's.
> 
> If an exception adds state and/or interface to the table, I agree that may justify its existence as a distinct type.

If all you're arguing is that something like StringException shouldn't exist because it doesn't add any additional member fields, then that's a much more reasonable thing to debate. I'm not quite sure I agree, but some of your responses seem to indicate that you don't want a rich exception hierarchy.

In the case of getopt, at _least_ adding a GetOptException with a field for the failed flag would be very valuable, and having additional derived types which indicate _why_ it failed would also be valuable. And in some cases at least, that would lead to more member fields in the derived exceptions (like the value of the flag if it were given a bad value).

I would argue however that there _are_ times when having a derived exception which has no additional data beyond its type rather than simply Exception can be useful - _especially_ when it's at the base of a larger hierarchy. For instance, if we had an IOException, you could know that whatever operation you were trying to do went badly because of an IO problem. You would probably need to handle it as a subclass of IOException to get any particularly useful information on how to handle the problem, but just knowing that it was an I/O problem could be enough in some cases.

I really think that whether adding an exception type which adds no additional member fields is a good idea should be evaluated on a case-by-case basis. We don't want to needlessly create a bunch of useless, uninformative exception types, but be we also want a rich enough exception hierarchy that it's possible to intelligently recover from exceptions.

- Jonathan M Davis
February 19, 2012
On 2/18/12 8:38 PM, Jonathan M Davis wrote:
> On Saturday, February 18, 2012 20:30:45 Andrei Alexandrescu wrote:
>> On 2/18/12 6:40 PM, H. S. Teoh wrote:
>>> One word: internationalization. Then toString() falls flat on its face.
>>
>> No. I happen to have some expertise in the area as I've participated to
>> two large and heavily internationalized systems. i18n has everything to
>> do with string tables and formatting templates and emphatically nothing
>> to do with exception hierarchies. The only possible link is that
>> exceptions should provide the necessary hooks.
>
> They do in that if you want to print a message because of that exception, you
> need to print something in the correct language, and that won't work with
> toString unless the exception type has built-in internationalization of some
> kind - regardless of what that internationalization mechanism might be.

Of course. toString is not a solution to internationalizing exceptions (or any complex messages).

Andrei


February 19, 2012
On 2/18/2012 3:13 PM, Andrei Alexandrescu wrote:
> On 2/18/12 4:26 PM, Jonathan M Davis wrote (abridged):
> GetOptException
> FlagArgumentMissingException
> InvalidFlagArgumentException
> UnknownFlagException
> FileException
> FileNotFoundException
> NotFileException
> NotDirException
> AccessDeniedException
>
> I died inside a little.

I think typed exceptions are a good idea, but something looks wrong with these.

(Also, having a large number of exception types is going to produce a lot of program size bloat. Remember, for EVERY class type, you've got the vtbl[], the .init data, and the TypeInfo. Going to town on exception types can really add this up.)
February 19, 2012
On 2/18/2012 7:56 PM, Zach wrote:
> On Sunday, 19 February 2012 at 01:29:40 UTC, Nick Sabalausky wrote:
>> Another one for the file of "Crazy shit Andrei says" ;)
>>
>> From experience, I (and clearly many others here) find a sparse, flat
>> exception hierarchy to be problematic and limiting. But even with a
>> rich detailed exception hierarchy, those (ie, Andrei) who want to
>> limit themselves to catching course-grained exceptions can do so,
>> thanks to the nature of subtyping. So why are we even discussing this?
>
> How about we revisit ancient design decisions which once held true...
> but no longer is the case due to our "god-language" being more expressive?
>
> In my experience an "exception hierarchy" is never good enough, it
> suffers from the same problems as most frameworks also do... they
> simplify/destroy too much info of from the original error.
>
> ex why don't we throw a closure? Of course we could go crazy with mixins
> and CTFE,CTTI,RTTI aswell... imho the goal should not be to do as good
> as java, the goal is progress! Java should copy our design if
> anything... we could have a very rich exception structure... without the
> need for a hierarchy.
>
> try(name) // try extended to support full closure syntax
> {
> DIR* dir = opendir(toStringz(name));
>
> if(dir==0 && errno==ENOTDIR)
> throw; // throws the entire try block as a closure
> }
>

My C++ experience revolves around some rather large codebases that do not have exceptions enabled at all.  The more I look into seeing what it would take to start using them, all I see are some pretty huge downsides:

The exact nature of the error for a lot of exceptions for like File I/O are very platform specific.  Throwing these objects effectively bubbles up highly platform specific data up to the caller, which infects the caller with the need to deal with platform specific data (posix codes vs GetLastError, vs various return values from the functions that failed etc).  This is not a good thing for keeping a codebase isolated from platform differences.

There has been seeing a huge shift in needing to make everything I work on threaded on a fine-grained level (game simulation, graphics rendering, various physics based systems and simulations, networking etc).  The way exceptions work, unwind the stack until someone 'cares', is not a good model in this environment.  Ideally everything is on its own thread or exists as a job in a job queue, or exists as some kind of node in a flow based system.  In these environments there is no caller on the _stack_ to unwind to.  You have to package up another async message with the failure and handle it somewhere else.  In many ways this is superior, as it solves the problem exceptions were created to solve : route errors to the proper code that 'cares'.

In the Von Neumann model this has been made difficult by the stack itself.  Thinking of exceptions as they are currently implemented in Java, C++, D, etc is automatically artificially constraining how they need to work.  Exceptions as they are now exist as a way to jump up the stack some arbitrary amount (until a handler is found).  The real problem that needs solving is 'route errors the most appropriate place available' with the constraint of 'keep the program in a working state'.  I would prefer a system that works equally well in both kinds of environments, as we are already mixing the styles, and switching code from one to the other requires a large amount of refactoring due to the differences in error handling.



February 19, 2012
"Zach" <mips@intel.arm> wrote in message news:tpxbylbgpvarpzzlpuuf@forum.dlang.org...
> On Sunday, 19 February 2012 at 01:29:40 UTC, Nick Sabalausky wrote:
>> Another one for the file of "Crazy shit Andrei says" ;)
>>
>> From experience, I (and clearly many others here) find a sparse, flat exception hierarchy to be problematic and limiting. But even with a rich detailed exception hierarchy, those (ie, Andrei) who want to limit themselves to catching course-grained exceptions can do so, thanks to the nature of subtyping. So why are we even discussing this?
>
> How about we revisit ancient design decisions which once held true... but no longer is the case due to our "god-language" being more expressive?
>

I'm fine with that when there's an alternative suggested that makes sense, or when there's an *actual* problem identified with the current way.

> In my experience an "exception hierarchy" is never good enough, it suffers from the same problems as most frameworks also do... they simplify/destroy too much info of from the original error.
>

The only problem I've ever had with them is that there's no templated catch blocks, so you can't handle two different exceptions with the same code without violating DRY or worse: catching the common base type and rethrowing when it's not what you wanted. Toss in templated catch blocks, and I've have no problem at all.

> ex why don't we throw a closure?

Haxe lets you throw literally anything. It's a useless pain in the ass that's along the same lines as VB being "flexible" enough to "allow" you to have arrays indexed from whatever random number you want. Adds no benefit, and just forces people to make sure to handle extra scenarios that aren't useful in the first place.

> Of course we could go crazy with mixins and CTFE,CTTI,RTTI aswell... imho the goal should not be to do as good as java, the goal is progress! Java should copy our design if anything... we could have a very rich exception structure... without the need for a hierarchy.
>
> try(name) // try extended to support full closure syntax
> {
>   DIR* dir = opendir(toStringz(name));
>
>   if(dir==0 && errno==ENOTDIR)
>     throw; // throws the entire try block as a closure
> }
>

What would the use of that be?


February 19, 2012
"Sean Cavanaugh" <WorksOnMyMachine@gmail.com> wrote in message news:jhpr9t$29i$1@digitalmars.com...
>
> My C++ experience revolves around some rather large codebases that do not have exceptions enabled at all.  The more I look into seeing what it would take to start using them, all I see are some pretty huge downsides:
>
> The exact nature of the error for a lot of exceptions for like File I/O are very platform specific.  Throwing these objects effectively bubbles up highly platform specific data up to the caller, which infects the caller with the need to deal with platform specific data (posix codes vs GetLastError, vs various return values from the functions that failed etc).  This is not a good thing for keeping a codebase isolated from platform differences.
>

Sounds like you're just dealing with some notably bad designed exceptions. I've never come across such a problem, and I've used exeptions extensively.


February 19, 2012
On Sunday, 19 February 2012 at 02:27:07 UTC, Andrei Alexandrescu wrote:
> On 2/18/12 6:28 PM, Jonathan M Davis wrote:
>> On Saturday, February 18, 2012 17:53:52 Andrei Alexandrescu wrote:
>>> On 2/18/12 5:47 PM, Jakob Ovrum wrote:
>>>> you are basically arguing against exceptions here
>>>
>>> I must have argued my question and point very poorly.
>>
>> You definitely seem to be arguing for a single Exception type
>
> No.

Yes.

Bernard



(This game is fun!)