www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Change the name of ArrayBoundsException in druntime

reply Jacob Carlborg <doobnet gmail.com> writes:
I think the name ArrayBoundsException should be changed to a more 
general name like BoundsException, OutOfBoundsException or 
IndexOutOfBoundsException. Then you can use the exception in every class 
that have some sort of index operation and not just for an array/array 
class.
Oct 22 2008
next sibling parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> wrote:
 I think the name ArrayBoundsException should be changed to a more general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.

2nded.
Oct 22 2008
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> wrote:
 I think the name ArrayBoundsException should be changed to a more general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei
Oct 22 2008
next sibling parent reply Max Samukha <samukha voliacable.com.removethis> writes:
On Wed, 22 Oct 2008 10:06:24 -0500, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> wrote:
 I think the name ArrayBoundsException should be changed to a more general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

Good idea. What about exceptions thrown from templated code? I suppose mixins and ordinary template instances should be treated differently: modue a; template Foo() { void Foo() { throw new Exception; } } ---- module b; alias Foo!() foo; // Exception's module should probably be 'a' mixin Foo; // Exception's module is 'b'?
Oct 22 2008
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Max Samukha wrote:
 On Wed, 22 Oct 2008 10:06:24 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> wrote:
 I think the name ArrayBoundsException should be changed to a more general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.


you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

Good idea. What about exceptions thrown from templated code? I suppose mixins and ordinary template instances should be treated differently: modue a; template Foo() { void Foo() { throw new Exception; } } ---- module b; alias Foo!() foo; // Exception's module should probably be 'a' mixin Foo; // Exception's module is 'b'?

That's a good point. By the way, where is Don's code to get the name of the current module? Andrei
Oct 22 2008
parent Don <nospam nospam.com.au> writes:
Denis Koroskin wrote:
 On Wed, 22 Oct 2008 20:25:15 +0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Max Samukha wrote:
 On Wed, 22 Oct 2008 10:06:24 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an 
 array/array
 class.


What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

mixins and ordinary template instances should be treated differently: modue a; template Foo() { void Foo() { throw new Exception; } } ---- module b; alias Foo!() foo; // Exception's module should probably be 'a' mixin Foo; // Exception's module is 'b'?

That's a good point. By the way, where is Don's code to get the name of the current module? Andrei

http://www.dsource.org/projects/meta/browser/trunk/meta/NameOf.d ?

That's not my code, although it's obviously based on my code (not acknowledged!)
Oct 23 2008
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 On Wed, 22 Oct 2008 19:06:24 +0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an array/array
 class.


I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

There is sometimes a need to differentiate between a specific exception and a generic one, even though the former or does nothing. typedef Exception MyException; // might be a good compromise try { throw new MyException("reason"); } catch (MyException e) { // catch concrete exception } catch (Exception e) { // catch generic exception } This code currently doesn't work, because compiler thinks that MyException and Exception are of the same type, which is wrong - MyException is kind of a subclass of Exception, as the following sample shows: typedef Exception MyException; void main() { MyException me = new MyException("reason"); Exception e = me; // implicit downcast me = e; // doesn't work, it is an upcast Object o = me; // ICE! :) } Could anyone put it into bugzilla? (I have no access to HTTP currently :()

I'd discussed that with Walter. He said that making typedefs full-fledged classes would be technically difficult. Andrei
Oct 22 2008
prev sibling next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

Yes, you _could_ use a field... but the "catch a subclass" style is already there and is supported by the language, so _why_ use a field? Which of the following is easier?: Option A: --------- try { new Socket(30587); } catch(SocketException e) { printf("Could not open socket\n"); } Option B: --------- try { new Socket(30587); } catch(Exception e) { if(e.type == ExceptionType.Socket) printf("Could not open socket\n"); else throw e; }
Oct 23 2008
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Robert Fraser wrote:
 Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

Yes, you _could_ use a field... but the "catch a subclass" style is already there and is supported by the language, so _why_ use a field? Which of the following is easier?: Option A: --------- try { new Socket(30587); } catch(SocketException e) { printf("Could not open socket\n"); } Option B: --------- try { new Socket(30587); } catch(Exception e) { if(e.type == ExceptionType.Socket) printf("Could not open socket\n"); else throw e; }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless. Andrei
Oct 23 2008
next sibling parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Thu, 23 Oct 2008 08:43:04 -0500,
Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

If you try every function separately, yes. But I think that the line between recoverable and non-recoverable exceptions is arbitrary and depends on the situation. It makes sense to try/catch a transaction, not separate calls. I can retry connection transaction if the socket open fails, but the whole upper-level transaction should fail if there is a database inconsistency or out of memory.
Oct 23 2008
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Sergey Gromov wrote:
 Thu, 23 Oct 2008 08:43:04 -0500,
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

If you try every function separately, yes. But I think that the line between recoverable and non-recoverable exceptions is arbitrary and depends on the situation. It makes sense to try/catch a transaction, not separate calls. I can retry connection transaction if the socket open fails, but the whole upper-level transaction should fail if there is a database inconsistency or out of memory.

I agree, but there's no need for a million types to support that. Andrei
Oct 23 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Andrei Alexandrescu" wrote
 Sergey Gromov wrote:
 Thu, 23 Oct 2008 08:43:04 -0500,
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

If you try every function separately, yes. But I think that the line between recoverable and non-recoverable exceptions is arbitrary and depends on the situation. It makes sense to try/catch a transaction, not separate calls. I can retry connection transaction if the socket open fails, but the whole upper-level transaction should fail if there is a database inconsistency or out of memory.

I agree, but there's no need for a million types to support that.

I agree that there's both a reason for subclassing and a reason for parameterizing. I don't want only one Exception class in the whole hierarchy that is parameterized as given in the example, but I also hate it when the reason for the exception is only implemented by the type of the exception. A good example is many OS errors, those should be parameterized on the errno (and should provide an easy way to build the string from strerror). -Steve
Oct 23 2008
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 A good example is many OS errors, those should be parameterized on the errno 
 (and should provide an easy way to build the string from strerror).

Yah, that's defined a couple of times in Phobos already, one is StdioException and the other I forgot... so silly. Andrei
Oct 23 2008
prev sibling next sibling parent reply David Gileadi <foo bar.com> writes:
Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

Yes, you _could_ use a field... but the "catch a subclass" style is already there and is supported by the language, so _why_ use a field? Which of the following is easier?: Option A: --------- try { new Socket(30587); } catch(SocketException e) { printf("Could not open socket\n"); } Option B: --------- try { new Socket(30587); } catch(Exception e) { if(e.type == ExceptionType.Socket) printf("Could not open socket\n"); else throw e; }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless. Andrei

Just an ill-considered idea from someone who has no idea whether it is even technically possible: try { new Socket(30587); } catch(Exception!(SocketConnect) e) { printf("Could not open socket\n"); } catch(Exception ex) { printf("Serious trouble--I probably shouldn't have caught this at all!\n"); } Granted, you'd still need to define SocketConnect and its ilk, but since they'd be simple (and in some cases empty) data containers they would be quick and easy to define, especially since you wouldn't need to implement all of Exception's constructors. Of course, this is back to catching by type again, so maybe it's not a good idea even if it is possible.
Oct 23 2008
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
David Gileadi wrote:
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an 
 array/array
 class.

2nded.

I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

Yes, you _could_ use a field... but the "catch a subclass" style is already there and is supported by the language, so _why_ use a field? Which of the following is easier?: Option A: --------- try { new Socket(30587); } catch(SocketException e) { printf("Could not open socket\n"); } Option B: --------- try { new Socket(30587); } catch(Exception e) { if(e.type == ExceptionType.Socket) printf("Could not open socket\n"); else throw e; }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless. Andrei

Just an ill-considered idea from someone who has no idea whether it is even technically possible: try { new Socket(30587); } catch(Exception!(SocketConnect) e) { printf("Could not open socket\n"); } catch(Exception ex) { printf("Serious trouble--I probably shouldn't have caught this at all!\n"); } Granted, you'd still need to define SocketConnect and its ilk, but since they'd be simple (and in some cases empty) data containers they would be quick and easy to define, especially since you wouldn't need to implement all of Exception's constructors. Of course, this is back to catching by type again, so maybe it's not a good idea even if it is possible.

It's very possible. Parameterizing Exception the same way Tuple is parameterized (with e.g. module name and name/value type pairs) is a great idea! Andrei
Oct 23 2008
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

It may be different in a user application, but in services it's fairly common to have specialized code for handling different exception types. And more importantly, it's common to want different exception types to propagate to different levels for handling. Sure, one could use a generic exception handler at each level that rethrows if the detected type isn't one that handler cares about but why do this when filtering on type is a language feature? For example, let's say I have a network service that's backed by a SQL database. My main program loop may look something like this: bool connected = false; while( true ) { try { while( true ) { auto r = acceptRequest(); scope(failure) r.tellFailed(); if( !connected ) connectToDB(); handleRequest( r ); } } catch( SqlException e ) { connected = false; log( e ); } catch( Exception e ) { log( e ); } } ... void handleRequest( Request r ) { scope(failure) r.tellFailed( "General error" ); try { // process r } catch( AuthException e ) { r.tellFailed( "Authentication failure" ); } catch( ValidationException e ) { r.tellFailed( "Invalid request format" ); } } Being able to trap specific types of exceptions makes this code cleaner and more succinct than it would be otherwise. If this weren't possible I'd have to trap, check, and rethrow certain exceptions at different levels to ensure that the proper handler saw them. Sean
Oct 23 2008
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Sean Kelly wrote:
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

It may be different in a user application, but in services it's fairly common to have specialized code for handling different exception types. And more importantly, it's common to want different exception types to propagate to different levels for handling. Sure, one could use a generic exception handler at each level that rethrows if the detected type isn't one that handler cares about but why do this when filtering on type is a language feature? For example, let's say I have a network service that's backed by a SQL database. My main program loop may look something like this: bool connected = false; while( true ) { try { while( true ) { auto r = acceptRequest(); scope(failure) r.tellFailed(); if( !connected ) connectToDB(); handleRequest( r ); } } catch( SqlException e ) { connected = false; log( e ); } catch( Exception e ) { log( e ); } } ... void handleRequest( Request r ) { scope(failure) r.tellFailed( "General error" ); try { // process r } catch( AuthException e ) { r.tellFailed( "Authentication failure" ); } catch( ValidationException e ) { r.tellFailed( "Invalid request format" ); } } Being able to trap specific types of exceptions makes this code cleaner and more succinct than it would be otherwise. If this weren't possible I'd have to trap, check, and rethrow certain exceptions at different levels to ensure that the proper handler saw them.

Thanks for fueling my argument. There's duplication in code examples, as in many other examples I've seen in favor of by-type handling. First example: catch( Exception e ) { if (e.origin = "sql") connected = false; log( e ); } Less code and no duplication. Second example is even starker: catch( AuthException e ) { r.tellFailed( e.toString ); } Clearly the need is to factor in the message to print in the exception, at least in this case and many like it. Andrei
Oct 23 2008
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Andrei Alexandrescu wrote:
 Sean Kelly wrote:
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

It may be different in a user application, but in services it's fairly common to have specialized code for handling different exception types. And more importantly, it's common to want different exception types to propagate to different levels for handling. Sure, one could use a generic exception handler at each level that rethrows if the detected type isn't one that handler cares about but why do this when filtering on type is a language feature? For example, let's say I have a network service that's backed by a SQL database. My main program loop may look something like this: bool connected = false; while( true ) { try { while( true ) { auto r = acceptRequest(); scope(failure) r.tellFailed(); if( !connected ) connectToDB(); handleRequest( r ); } } catch( SqlException e ) { connected = false; log( e ); } catch( Exception e ) { log( e ); } } ... void handleRequest( Request r ) { scope(failure) r.tellFailed( "General error" ); try { // process r } catch( AuthException e ) { r.tellFailed( "Authentication failure" ); } catch( ValidationException e ) { r.tellFailed( "Invalid request format" ); } } Being able to trap specific types of exceptions makes this code cleaner and more succinct than it would be otherwise. If this weren't possible I'd have to trap, check, and rethrow certain exceptions at different levels to ensure that the proper handler saw them.

Thanks for fueling my argument. There's duplication in code examples, as in many other examples I've seen in favor of by-type handling. First example: catch( Exception e ) { if (e.origin = "sql") connected = false; log( e ); } Less code and no duplication. Second example is even starker: catch( AuthException e ) { r.tellFailed( e.toString ); } Clearly the need is to factor in the message to print in the exception, at least in this case and many like it. Andrei

By the way, this each-exception-has-its-type crap is my #2 pet peeve after "Follow carefully my pocket watch... OO is good for everything... OO is good for everything... to use, inherit... to use, inherit..." Andrei
Oct 23 2008
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 4:08 AM, Andrei Alexandrescu
 By the way, this each-exception-has-its-type crap is my #2 pet peeve after
 "Follow carefully my pocket watch... OO is good for everything... OO is good
 for everything... to use, inherit... to use, inherit..."

Interesting point. The whole catch(A){} catch(B){} catch(C){} thing is basically if-then-else on very similar types, which is exactly what the OO crowd says you should try to avoid in any other situation. You should be using polymorphism!

Yes!
 But ok, types are good for one thing, and that's ensuring global
 uniqueness.  That seems to be the real point of the billion exception
 types, to give them unique identifiers that the compiler can check.
 You can give your exceptions a typecode or a string identifier, like
 your origin=="sql", but then the compiler won't tell you if your type
 is unique.  And it won't tell you there's a problem if you mistakenly
 type origin=="SQL" instead of "sql".

The module name can supplant that.
 I think it boils down to a kind of static typing vs dynamic typing argument.

To some extent, yes. But, I think an adept of static typing should also recognize when it brings nothing to the table, and IMHO exceptions are one of those cases. Andrei
Oct 23 2008
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Andrei Alexandrescu" wrote
 Sean Kelly wrote:
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

It may be different in a user application, but in services it's fairly common to have specialized code for handling different exception types. And more importantly, it's common to want different exception types to propagate to different levels for handling. Sure, one could use a generic exception handler at each level that rethrows if the detected type isn't one that handler cares about but why do this when filtering on type is a language feature? For example, let's say I have a network service that's backed by a SQL database. My main program loop may look something like this: bool connected = false; while( true ) { try { while( true ) { auto r = acceptRequest(); scope(failure) r.tellFailed(); if( !connected ) connectToDB(); handleRequest( r ); } } catch( SqlException e ) { connected = false; log( e ); } catch( Exception e ) { log( e ); } } ... void handleRequest( Request r ) { scope(failure) r.tellFailed( "General error" ); try { // process r } catch( AuthException e ) { r.tellFailed( "Authentication failure" ); } catch( ValidationException e ) { r.tellFailed( "Invalid request format" ); } } Being able to trap specific types of exceptions makes this code cleaner and more succinct than it would be otherwise. If this weren't possible I'd have to trap, check, and rethrow certain exceptions at different levels to ensure that the proper handler saw them.

Thanks for fueling my argument. There's duplication in code examples, as in many other examples I've seen in favor of by-type handling. First example: catch( Exception e ) { if (e.origin = "sql") connected = false; log( e ); } Less code and no duplication. Second example is even starker: catch( AuthException e ) { r.tellFailed( e.toString ); } Clearly the need is to factor in the message to print in the exception, at least in this case and many like it.

For the second example, you are assuming that ValidationException is a subclass of AuthException. I think in this case, ValidationException and AuthException might share a common parent (SqlException) which you do NOT want to catch. It is advantageous in this case to have both a hierarchy through inheritance and a hierarchy through parameters. Here's another idea, to avoid rethrows, what about some pre-handler code that tests if an exception is what you want? Perhaps the same mechanism that is used by template constraints: catch(SqlException e) if (e.reason is Auth || e.reason is Validation) { r.tellFailed(e.toString()); } That gives you the same mechanism used with typing and without the rethrows, without creating N subclasses of SqlException, and without multiple repetitive blocks that do the same thing. It looks more readable to me too. Not sure how exception code works, so I don't know how plausible this is. -Steve
Oct 23 2008
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 "Andrei Alexandrescu" wrote
 Sean Kelly wrote:
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

common to have specialized code for handling different exception types. And more importantly, it's common to want different exception types to propagate to different levels for handling. Sure, one could use a generic exception handler at each level that rethrows if the detected type isn't one that handler cares about but why do this when filtering on type is a language feature? For example, let's say I have a network service that's backed by a SQL database. My main program loop may look something like this: bool connected = false; while( true ) { try { while( true ) { auto r = acceptRequest(); scope(failure) r.tellFailed(); if( !connected ) connectToDB(); handleRequest( r ); } } catch( SqlException e ) { connected = false; log( e ); } catch( Exception e ) { log( e ); } } ... void handleRequest( Request r ) { scope(failure) r.tellFailed( "General error" ); try { // process r } catch( AuthException e ) { r.tellFailed( "Authentication failure" ); } catch( ValidationException e ) { r.tellFailed( "Invalid request format" ); } } Being able to trap specific types of exceptions makes this code cleaner and more succinct than it would be otherwise. If this weren't possible I'd have to trap, check, and rethrow certain exceptions at different levels to ensure that the proper handler saw them.

in many other examples I've seen in favor of by-type handling. First example: catch( Exception e ) { if (e.origin = "sql") connected = false; log( e ); } Less code and no duplication. Second example is even starker: catch( AuthException e ) { r.tellFailed( e.toString ); } Clearly the need is to factor in the message to print in the exception, at least in this case and many like it.

For the second example, you are assuming that ValidationException is a subclass of AuthException.

Sorry, I meant to catch Exception. My point was, if I want to print an informative message, the exception should be able to provide it without having to encode it in its type.
 I think in this case, ValidationException and AuthException might share a 
 common parent (SqlException) which you do NOT want to catch.  It is 
 advantageous in this case to have both a hierarchy through inheritance and a 
 hierarchy through parameters.

 Here's another idea, to avoid rethrows, what about some pre-handler code 
 that tests if an exception is what you want?  Perhaps the same mechanism 
 that is used by template constraints:
 
 catch(SqlException e) if (e.reason is Auth || e.reason is Validation)
 {
    r.tellFailed(e.toString());
 }

I think we're a bit too immersed in the "what can we add to the language". In this case, for example, I see no reason for the "if" to be moved inside and call it a day. Andrei
Oct 23 2008
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Andrei Alexandrescu" wrote
 Steven Schveighoffer wrote:
 "Andrei Alexandrescu" wrote
 Sean Kelly wrote:
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

common to have specialized code for handling different exception types. And more importantly, it's common to want different exception types to propagate to different levels for handling. Sure, one could use a generic exception handler at each level that rethrows if the detected type isn't one that handler cares about but why do this when filtering on type is a language feature? For example, let's say I have a network service that's backed by a SQL database. My main program loop may look something like this: bool connected = false; while( true ) { try { while( true ) { auto r = acceptRequest(); scope(failure) r.tellFailed(); if( !connected ) connectToDB(); handleRequest( r ); } } catch( SqlException e ) { connected = false; log( e ); } catch( Exception e ) { log( e ); } } ... void handleRequest( Request r ) { scope(failure) r.tellFailed( "General error" ); try { // process r } catch( AuthException e ) { r.tellFailed( "Authentication failure" ); } catch( ValidationException e ) { r.tellFailed( "Invalid request format" ); } } Being able to trap specific types of exceptions makes this code cleaner and more succinct than it would be otherwise. If this weren't possible I'd have to trap, check, and rethrow certain exceptions at different levels to ensure that the proper handler saw them.

in many other examples I've seen in favor of by-type handling. First example: catch( Exception e ) { if (e.origin = "sql") connected = false; log( e ); } Less code and no duplication. Second example is even starker: catch( AuthException e ) { r.tellFailed( e.toString ); } Clearly the need is to factor in the message to print in the exception, at least in this case and many like it.

For the second example, you are assuming that ValidationException is a subclass of AuthException.

Sorry, I meant to catch Exception. My point was, if I want to print an informative message, the exception should be able to provide it without having to encode it in its type.

Sure, but then your example becomes: catch(Exception e) { if(e.reason is Auth || e.reason is Validation) r.tellFailed(e.toString()); else throw e; } Not that it looks terrible, but I just want it to be clear that your one-liner isn't sufficient.
 I think in this case, ValidationException and AuthException might share a 
 common parent (SqlException) which you do NOT want to catch.  It is 
 advantageous in this case to have both a hierarchy through inheritance 
 and a hierarchy through parameters.

 Here's another idea, to avoid rethrows, what about some pre-handler code 
 that tests if an exception is what you want?  Perhaps the same mechanism 
 that is used by template constraints:

 catch(SqlException e) if (e.reason is Auth || e.reason is Validation)
 {
    r.tellFailed(e.toString());
 }

I think we're a bit too immersed in the "what can we add to the language". In this case, for example, I see no reason for the "if" to be moved inside and call it a day.

A fair point. It might help in situations like this (with your philosophy of not subclassing for specific reasons): try { try { ... } catch(SqlException sql) { if(sql.reason == Auth || sql.reason == Validation) changeUsertokensAndRetry(); // recovery else throw sql; } } catch(Exception e) { r.tellFailed(e.toString()); } Would then become: try { ... } catch(SqlException sql) if (sql.reason == Auth || sql.reason == Validation) { changeUsertokensAndRetry(); } catch(Exception e) { r.tellFailed(e.toString()); } instead of one giant catch block that catches all exceptions. Basically, it augments the code that determines where the exception is caught to check for more than just type. But I don't know how common stuff like that is. -Steve
Oct 23 2008
prev sibling parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Thu, 23 Oct 2008 14:44:46 -0500,
Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an 
 informative message, the exception should be able to provide it without 
 having to encode it in its type.

It's all nice and simple until you want to localize. Then all your 'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.
Oct 23 2008
next sibling parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Fri, 24 Oct 2008 06:55:27 +0900,
Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 6:41 AM, Sergey Gromov <snake.scaly gmail.com> wrote:
 Thu, 23 Oct 2008 14:44:46 -0500,
 Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an
 informative message, the exception should be able to provide it without
 having to encode it in its type.

It's all nice and simple until you want to localize. Then all your 'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.

Just use poedit or whatever to provide localizations of the messages. I don't see how this has bearing on the discussion at all.

Where do I get all the messages library may throw? How can I be sure that the message won't change in the next release, silently discarding my translation? Informative library-provided messages are a myth. The only informative part is an exception type, or a standardized error code--which is even better for localization. The "writeln(e.toString())" approach only suffices for quick utilities not meant for use by an end user.
Oct 23 2008
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Sergey Gromov wrote:
 Fri, 24 Oct 2008 06:55:27 +0900,
 Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 6:41 AM, Sergey Gromov <snake.scaly gmail.com> wrote:
 Thu, 23 Oct 2008 14:44:46 -0500,
 Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an
 informative message, the exception should be able to provide it without
 having to encode it in its type.

'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.

I don't see how this has bearing on the discussion at all.

Where do I get all the messages library may throw? How can I be sure that the message won't change in the next release, silently discarding my translation? Informative library-provided messages are a myth. The only informative part is an exception type, or a standardized error code--which is even better for localization. The "writeln(e.toString())" approach only suffices for quick utilities not meant for use by an end user.

I agree. For true localization, string tables are necessary. Andrei
Oct 23 2008
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Sergey Gromov wrote:
 Thu, 23 Oct 2008 14:44:46 -0500,
 Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an 
 informative message, the exception should be able to provide it without 
 having to encode it in its type.

It's all nice and simple until you want to localize. Then all your 'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.

No, translation would have to be provided via a string table. And guess who provides the key for that table. Andrei
Oct 23 2008
parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Fri, 24 Oct 2008 08:54:49 +0900,
Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 6:47 AM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Sergey Gromov wrote:
 Thu, 23 Oct 2008 14:44:46 -0500,
 Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an
 informative message, the exception should be able to provide it without
 having to encode it in its type.

It's all nice and simple until you want to localize. Then all your 'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.

No, translation would have to be provided via a string table. And guess who provides the key for that table.

But what Sergey is pointing out is that 1) if you rely on a human readable string for the key, then you have to fix things when some maintenance programmer fixes a spelling error in the message 2) if you rely on human readable strings in that are in 3rd party libraries then you have to find all those strings some how. Could be difficult without source. So if you're going to translate then having an actual key, a unique identifying symbol not meant for human consumption, is a better approach.

Correct. Thank you for putting this together. But there is even more to it than that: the library exceptions are usually too low-level and too specific to spit at the user as is. They need to be analysed and converted into a more appropriate form or action. And exception must provide means for such analysis other than message string parsing.
Oct 23 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
Sergey Gromov wrote:
 Fri, 24 Oct 2008 08:54:49 +0900,
 Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 6:47 AM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Sergey Gromov wrote:
 Thu, 23 Oct 2008 14:44:46 -0500,
 Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an
 informative message, the exception should be able to provide it without
 having to encode it in its type.

'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.

provides the key for that table.

1) if you rely on a human readable string for the key, then you have to fix things when some maintenance programmer fixes a spelling error in the message 2) if you rely on human readable strings in that are in 3rd party libraries then you have to find all those strings some how. Could be difficult without source. So if you're going to translate then having an actual key, a unique identifying symbol not meant for human consumption, is a better approach.

Correct. Thank you for putting this together. But there is even more to it than that: the library exceptions are usually too low-level and too specific to spit at the user as is. They need to be analysed and converted into a more appropriate form or action. And exception must provide means for such analysis other than message string parsing.

Right -- and what action the program was taking to cause the exception also must be taken into account.
Oct 23 2008
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Andrei Alexandrescu wrote:
 Sean Kelly wrote:
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
     new Socket(30587);
 }
 catch(Exception e)
 {
     if(e.type == ExceptionType.Socket)
         printf("Could not open socket\n");
     else
         throw e;
 }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

It may be different in a user application, but in services it's fairly common to have specialized code for handling different exception types. And more importantly, it's common to want different exception types to propagate to different levels for handling. Sure, one could use a generic exception handler at each level that rethrows if the detected type isn't one that handler cares about but why do this when filtering on type is a language feature? For example, let's say I have a network service that's backed by a SQL database. My main program loop may look something like this: bool connected = false; while( true ) { try { while( true ) { auto r = acceptRequest(); scope(failure) r.tellFailed(); if( !connected ) connectToDB(); handleRequest( r ); } } catch( SqlException e ) { connected = false; log( e ); } catch( Exception e ) { log( e ); } } ... void handleRequest( Request r ) { scope(failure) r.tellFailed( "General error" ); try { // process r } catch( AuthException e ) { r.tellFailed( "Authentication failure" ); } catch( ValidationException e ) { r.tellFailed( "Invalid request format" ); } } Being able to trap specific types of exceptions makes this code cleaner and more succinct than it would be otherwise. If this weren't possible I'd have to trap, check, and rethrow certain exceptions at different levels to ensure that the proper handler saw them.

Thanks for fueling my argument. There's duplication in code examples, as in many other examples I've seen in favor of by-type handling. First example: catch( Exception e ) { if (e.origin = "sql") connected = false; log( e ); } Less code and no duplication. Second example is even starker: catch( AuthException e ) { r.tellFailed( e.toString ); } Clearly the need is to factor in the message to print in the exception, at least in this case and many like it.

Hm... you're right. So here we really have two classes of exceptions, one concerning the request itself and another concerning meta issues like connection failures. Meta issues can all be caught together as Exception, so the only specialized handler would be in handleRequest() as something like: catch( RequestException e ) { r.tellFailed( e.toString ); } Really, all I was getting at is that I don't think it's a good idea for there to be no type distinctions at all. The tricky thing, as you've clearly pointed out, is to distill those distinctions to only the pertinent ones rather than simply designating a new type for every error. Sean
Oct 23 2008
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Sean Kelly wrote:
 Really, all I was getting at is that I don't think it's a good idea for 
 there to be no type distinctions at all.  The tricky thing, as you've 
 clearly pointed out, is to distill those distinctions to only the 
 pertinent ones rather than simply designating a new type for every error.

Well put. But I think it's way more effective to start conservatively (with few exception types) and fan out, instead of as it is now - the first thing to be found in each std/ file ever is emperor's hairy belly pretending it's wearing a great cardigan. In fact, by this I'm requesting community's permission to throw (sic!) a large fraction of the exception classes out of Phobos. Andrei
Oct 23 2008
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Andrei Alexandrescu wrote:
             r.tellFailed( e.toString );

Now that's just wrong. toString should be used for internal debugging purposes. If there's a recoverable error and you want to show it to the user, in a big product, it will need to be internationalized. The worry about what language to display the string in should not be given to the exception thrower, it should be given to the catcher.
Oct 23 2008
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

Yes, you _could_ use a field... but the "catch a subclass" style is already there and is supported by the language, so _why_ use a field? Which of the following is easier?: Option A: --------- try { new Socket(30587); } catch(SocketException e) { printf("Could not open socket\n"); } Option B: --------- try { new Socket(30587); } catch(Exception e) { if(e.type == ExceptionType.Socket) printf("Could not open socket\n"); else throw e; }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless. Andrei

So in most cases you don't need it... But why throw it out for the cases in which you do (or make it harder to use). In other words, is there any _harm_ being done by having a large exception hierarchy?
Oct 23 2008
prev sibling parent "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Oct 24, 2008 at 7:45 AM, Sergey Gromov <snake.scaly gmail.com> wrote:
 Fri, 24 Oct 2008 06:55:27 +0900,
 Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 6:41 AM, Sergey Gromov <snake.scaly gmail.com> wrote:
 Thu, 23 Oct 2008 14:44:46 -0500,
 Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an
 informative message, the exception should be able to provide it without
 having to encode it in its type.

It's all nice and simple until you want to localize. Then all your 'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.

Just use poedit or whatever to provide localizations of the messages. I don't see how this has bearing on the discussion at all.

Where do I get all the messages library may throw?

Ah, I see your point now. I thought this was still about making distinct types for every exception. I missed the comment from Andrei. --bb
Oct 23 2008
prev sibling parent "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Oct 24, 2008 at 6:47 AM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Sergey Gromov wrote:
 Thu, 23 Oct 2008 14:44:46 -0500,
 Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an
 informative message, the exception should be able to provide it without
 having to encode it in its type.

It's all nice and simple until you want to localize. Then all your 'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.

No, translation would have to be provided via a string table. And guess who provides the key for that table.

But what Sergey is pointing out is that 1) if you rely on a human readable string for the key, then you have to fix things when some maintenance programmer fixes a spelling error in the message 2) if you rely on human readable strings in that are in 3rd party libraries then you have to find all those strings some how. Could be difficult without source. So if you're going to translate then having an actual key, a unique identifying symbol not meant for human consumption, is a better approach. --bb
Oct 23 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Denis Koroskin wrote:
 On Wed, 22 Oct 2008 16:22:02 +0400, Jarrett Billingsley 
 <jarrett.billingsley gmail.com> wrote:
 
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

Agreed. BTW, why it is not an Error but Exception?

The Error class was created shortly before release and I didn't get around to reclassifying the exceptions in druntime. From memory though, I think that OutOfMemoryException and UtfException should remain as-is, but the remaining exceptions should probably be errors. Any objections? And as for ArrayBoundsException... how about IndexOutOfBoundsError. It's long, but probably the most self-explanatory. Also, any value in retaining ArrayBoundsError and having it subclass this? I'd think not, but figured I'd ask anyway. Sean
Oct 22 2008
next sibling parent Jacob Carlborg <doobnet gmail.com> writes:
Sean Kelly wrote:
 Denis Koroskin wrote:
 On Wed, 22 Oct 2008 16:22:02 +0400, Jarrett Billingsley 
 <jarrett.billingsley gmail.com> wrote:

 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

Agreed. BTW, why it is not an Error but Exception?

The Error class was created shortly before release and I didn't get around to reclassifying the exceptions in druntime. From memory though, I think that OutOfMemoryException and UtfException should remain as-is, but the remaining exceptions should probably be errors. Any objections? And as for ArrayBoundsException... how about IndexOutOfBoundsError. It's long, but probably the most self-explanatory. Also, any value in retaining ArrayBoundsError and having it subclass this? I'd think not, but figured I'd ask anyway. Sean

Yes it's longer but I gave three suggestions. I just don't want Array in the name so it can be used in general case.
Oct 22 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Sean Kelly Wrote:

 Denis Koroskin wrote:
 On Wed, 22 Oct 2008 16:22:02 +0400, Jarrett Billingsley 
 <jarrett.billingsley gmail.com> wrote:
 
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

Agreed. BTW, why it is not an Error but Exception?

The Error class was created shortly before release and I didn't get around to reclassifying the exceptions in druntime. From memory though, I think that OutOfMemoryException and UtfException should remain as-is, but the remaining exceptions should probably be errors. Any objections?

What is the criteria for choosing exception verses error? How would this tie into non-recoverable errors discussed with pure function exception handling?
 
 And as for ArrayBoundsException... how about IndexOutOfBoundsError. 
 It's long, but probably the most self-explanatory.  Also, any value in 
 retaining ArrayBoundsError and having it subclass this?  I'd think not, 
 but figured I'd ask anyway.
 
 
 Sean

Oct 22 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
Jason House wrote:
 Sean Kelly Wrote:
 
 Denis Koroskin wrote:
 On Wed, 22 Oct 2008 16:22:02 +0400, Jarrett Billingsley 
 <jarrett.billingsley gmail.com> wrote:

 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.



around to reclassifying the exceptions in druntime. From memory though, I think that OutOfMemoryException and UtfException should remain as-is, but the remaining exceptions should probably be errors. Any objections?

What is the criteria for choosing exception verses error? How would this tie into non-recoverable errors discussed with pure function exception handling?

Errors represent situations which are typically non-recoverable--program logic errors, for example, or situations where data corruption may have occurred--while Exceptions represent the bulk of normal execution errors, including OutOfMemory conditions. Regarding pure functions... are you talking about the nothrow guarantee? I haven't given it much thought, but I'd be inclined to say that it's legal for a nothrow function to actually throw a child of Error but not Exception. That ignores OutOfMemoryException though, which is something that the programmer shouldn't have to handle. At the same time, I'd consider an out of memory condition to be quite recoverable, so... Sean
Oct 22 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org> wrote:
 Errors represent situations which are typically non-recoverable--program
 logic errors, for example, or situations where data corruption may have
 occurred--while Exceptions represent the bulk of normal execution errors,
 including OutOfMemory conditions.

How, pray tell, is an app supposed to recover from an out-of-memory condition?

By releasing dynamically allocated memory. I'd expect some to be released automatically as the stack is unrolled to the catch point anyway. For example: void main() { try { fn(); } catch( Exception e ) {} int[] x = new int[16384]; } void fn() { int[] x = new int[16384]; fn(); } Eventually this app will run out of memory (hopefully before it runs out of stack space) and an OutOfMemoryException will be thrown. As the stack is unwound, all valid references to this memory will be released. So the allocation in main() should trigger a collection which frees up all the now-unreferenced memory, thus allowing the allocation in main() to succeed. For manual recovery, consider an app that does a great deal of internal caching. On an OutOfMemory condition the app could clear its caches and then retry the operation. This is probably a bad example, but I think the general idea of trapping and recovering from such a state is potentially valid. Sean
Oct 22 2008
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Sean Kelly wrote:
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org> 
 wrote:
 Errors represent situations which are typically non-recoverable--program
 logic errors, for example, or situations where data corruption may have
 occurred--while Exceptions represent the bulk of normal execution 
 errors,
 including OutOfMemory conditions.

How, pray tell, is an app supposed to recover from an out-of-memory condition?

By releasing dynamically allocated memory. I'd expect some to be released automatically as the stack is unrolled to the catch point anyway. For example: void main() { try { fn(); } catch( Exception e ) {} int[] x = new int[16384]; } void fn() { int[] x = new int[16384]; fn(); } Eventually this app will run out of memory (hopefully before it runs out of stack space) and an OutOfMemoryException will be thrown. As the stack is unwound, all valid references to this memory will be released. So the allocation in main() should trigger a collection which frees up all the now-unreferenced memory, thus allowing the allocation in main() to succeed. For manual recovery, consider an app that does a great deal of internal caching. On an OutOfMemory condition the app could clear its caches and then retry the operation. This is probably a bad example, but I think the general idea of trapping and recovering from such a state is potentially valid. Sean

Didn't see this discussion before I went off my tirade. I agree it's recoverable and in a perfect world this would be so, but look through any large codebase for how many catch(Exception) blocks there are. I'll bet you that NONE of the general catch(Exception) blocks (except the ones that print an error and exit the program) expect to see, or are prepared for, an out of memory exception. Asking programmers to think about out of memory errors is too much. We're trained to assume computers have infinite memory and when they run out, the system/runtime is supposed to do drastic things like crashing our programs - not start introducing strange logic errors all over the place because programmers didn't realize their catch(Exception) blocks had to deal with more than "file doesn't exist"
Oct 23 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
Robert Fraser wrote:
 
 Didn't see this discussion before I went off my tirade. I agree it's 
 recoverable and in a perfect world this would be so, but look through 
 any large codebase for how many catch(Exception) blocks there are. I'll 
 bet you that NONE of the general catch(Exception) blocks (except the 
 ones that print an error and exit the program) expect to see, or are 
 prepared for, an out of memory exception.

I'd argue that anyone who catches Exception, prints a message, and continues blindly is just asking for trouble. But this seems to have become an ingrained practice anyway, so it's a fair point. However, I'm not sure this is sufficient reason to relabel an out of memory condition as ostensibly unrecoverable.
 Asking programmers to think about out of memory errors is too much. 
 We're trained to assume computers have infinite memory and when they run 
 out, the system/runtime is supposed to do drastic things like crashing 
 our programs - not start introducing strange logic errors all over the 
 place because programmers didn't realize their catch(Exception) blocks 
 had to deal with more than "file doesn't exist"

Perhaps I'm simply getting old... when did memory use become irrelevant? I grant that making an application exception safe is more difficult if out of memory conditions are considered recoverable, but I don't think it's tremendously more difficult. Sean
Oct 23 2008
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Sean Kelly wrote:
 Perhaps I'm simply getting old... when did memory use become irrelevant? 
  I grant that making an application exception safe is more difficult if 
 out of memory conditions are considered recoverable, but I don't think 
 it's tremendously more difficult.

I'm currently studying Computer Engineering at university. I don't think a single programming course I've taken has _mentioned_ running out of memory (next quarter I'm taking Operating Systems, so hopefully that will). One class mentioned memory complexity as a side issue, but never got into it. Even at work, I've never been asked to think about it.
Oct 23 2008
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 10:42 AM, Robert Fraser
 <fraserofthenight gmail.com> wrote:
 Sean Kelly wrote:
 Perhaps I'm simply getting old... when did memory use become irrelevant?
  I grant that making an application exception safe is more difficult if out
 of memory conditions are considered recoverable, but I don't think it's
 tremendously more difficult.

single programming course I've taken has _mentioned_ running out of memory (next quarter I'm taking Operating Systems, so hopefully that will). One class mentioned memory complexity as a side issue, but never got into it. Even at work, I've never been asked to think about it.

People do still develop for embedded devices with small memory and/or no virtual memory. I'm pretty sure it's still a serious concern if you live in that world. --bb

I'm not saying it doesn't come up in practice; I'm saying developers are trained not to think about it in most cases. And programming to handle a small amount of memory is a different problem than programming to gracefully fail when the program runs out of memory (for example, my program might only use 10k of RAM... but if that 10k isn't there, it might just crash with an error message). The problem with an OutOfMemoryError being treated as an Exception is that if there are many catch(Exception) blocks, an out-of-memory error will propagate logic bugs across the program (since no one is cleaning up the memory, most allocations will fail). So instead of a nice, clean error, the suer will experience weird and frustrating behavior that doesn't mention memory at all.
Oct 24 2008
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Jesse Phillips wrote:
 On Fri, 24 Oct 2008 16:04:53 -0700, Robert Fraser wrote:
 
 Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 10:42 AM, Robert Fraser
 <fraserofthenight gmail.com> wrote:
 Sean Kelly wrote:
 Perhaps I'm simply getting old... when did memory use become
 irrelevant?
  I grant that making an application exception safe is more difficult
  if out
 of memory conditions are considered recoverable, but I don't think
 it's tremendously more difficult.

think a single programming course I've taken has _mentioned_ running out of memory (next quarter I'm taking Operating Systems, so hopefully that will). One class mentioned memory complexity as a side issue, but never got into it. Even at work, I've never been asked to think about it.

no virtual memory. I'm pretty sure it's still a serious concern if you live in that world. --bb

trained not to think about it in most cases. And programming to handle a small amount of memory is a different problem than programming to gracefully fail when the program runs out of memory (for example, my program might only use 10k of RAM... but if that 10k isn't there, it might just crash with an error message). The problem with an OutOfMemoryError being treated as an Exception is that if there are many catch(Exception) blocks, an out-of-memory error will propagate logic bugs across the program (since no one is cleaning up the memory, most allocations will fail). So instead of a nice, clean error, the suer will experience weird and frustrating behavior that doesn't mention memory at all.

The problem with it being an error is that the programmer has no way to catch and remain usable,

Sure there is: catch(OutOfMemoryError) Just like in Java or .Net. The only difference is that it's not caught by a general catch(Exception)
 leaving the user blissfully unaware he needs to 
 buy more ram. If there are many catch(Exception)'s around, the programmer 
 needs to rethink what he is doing when creating a stable program.

Probably. But when you have a team of 300 programmers, this is a bit harder to do, and catch(Exception) _is_ a powerful tool for generalized recoverable error handling.
 D doesn't force a try or throw of exceptions for this very reason; people 
 usually use the catch(Exception) because they don't know what needs to be 
 caught and don't care but are forced to catch it, not because their 
 program is crashing from an exception (well, that is what I do).

People also use it to say to the user "this didn't work; try something else"? In 99% of cases, this is fine, but when memory is involved, the programmer has a whole lot more to think about and would often want to catch the memory exception at a higher level.
Oct 25 2008
parent Sean Kelly <sean invisibleduck.org> writes:
Jesse Phillips wrote:
 On Sat, 25 Oct 2008 15:45:51 -0700, Robert Fraser wrote:
 
 Jesse Phillips wrote:
 D doesn't force a try or throw of exceptions for this very reason;
 people usually use the catch(Exception) because they don't know what
 needs to be caught and don't care but are forced to catch it, not
 because their program is crashing from an exception (well, that is what
 I do).

else"? In 99% of cases, this is fine, but when memory is involved, the programmer has a whole lot more to think about and would often want to catch the memory exception at a higher level.

Oops, from past discussions about the difference I somehow got the idea that an Error couldn't be caught. While out of memory still falls under recoverable, I can see why putting greater importance over other exceptions would be good.

After some thought, I'm inclined to agree. While an OOM condition might be recoverable without any explicit effort, I think it's a good idea to encourage that it receive special handling by classifying it as an Error. Since D is a systems language I don't consider any error condition to be necessarily unrecoverable anyway, so reclassifying OutOfMemory doesn't imply anything to me other than that it should be handled explicitly rather than accidentally by trapping and tossing out out as an Exception. Sean
Oct 31 2008
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 On Thu, 23 Oct 2008 04:02:22 +0400, Sean Kelly <sean invisibleduck.org> 
 wrote:
 
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org> 
 wrote:
 Errors represent situations which are typically 
 non-recoverable--program
 logic errors, for example, or situations where data corruption may have
 occurred--while Exceptions represent the bulk of normal execution 
 errors,
 including OutOfMemory conditions.

condition?

By releasing dynamically allocated memory. I'd expect some to be released automatically as the stack is unrolled to the catch point anyway. For example: void main() { try { fn(); } catch( Exception e ) {} int[] x = new int[16384]; } void fn() { int[] x = new int[16384]; fn(); } Eventually this app will run out of memory (hopefully before it runs out of stack space) and an OutOfMemoryException will be thrown. As the stack is unwound, all valid references to this memory will be released. So the allocation in main() should trigger a collection which frees up all the now-unreferenced memory, thus allowing the allocation in main() to succeed. For manual recovery, consider an app that does a great deal of internal caching. On an OutOfMemory condition the app could clear its caches and then retry the operation. This is probably a bad example, but I think the general idea of trapping and recovering from such a state is potentially valid. Sean

I think that OutOfMemoryException should *not* be recoverable. Instead, language should provide some hookable callback (like onOutOfMemoryError()) which is called when memory limit is reached so that program may free some unused memory (which is held by user since it is not garbage-collected) and tries to allocate the memory again without failure (return true from callback). User might decide to re-throw some other kind of *exception*, like NotEnoughMemoryException(), to catch and recover, or pass it (return false from callback) which in turn will finally throw OutOfMemoryError().

But one of the best things possible to do is unwind the stack and fall back to a higher position with less state. A function cannot do that, an exception can. Why do you guys want to avoid exceptions in one of the few cases when they are exactly, but exactly what the doctor prescribed? Andrei
Oct 23 2008
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 On Thu, 23 Oct 2008 17:47:52 +0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Denis Koroskin wrote:
 On Thu, 23 Oct 2008 04:02:22 +0400, Sean Kelly 
 <sean invisibleduck.org> wrote:

 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly 
 <sean invisibleduck.org> wrote:
 Errors represent situations which are typically 
 non-recoverable--program
 logic errors, for example, or situations where data corruption may 
 have
 occurred--while Exceptions represent the bulk of normal execution 
 errors,
 including OutOfMemory conditions.

out-of-memory condition?

By releasing dynamically allocated memory. I'd expect some to be released automatically as the stack is unrolled to the catch point anyway. For example: void main() { try { fn(); } catch( Exception e ) {} int[] x = new int[16384]; } void fn() { int[] x = new int[16384]; fn(); } Eventually this app will run out of memory (hopefully before it runs out of stack space) and an OutOfMemoryException will be thrown. As the stack is unwound, all valid references to this memory will be released. So the allocation in main() should trigger a collection which frees up all the now-unreferenced memory, thus allowing the allocation in main() to succeed. For manual recovery, consider an app that does a great deal of internal caching. On an OutOfMemory condition the app could clear its caches and then retry the operation. This is probably a bad example, but I think the general idea of trapping and recovering from such a state is potentially valid. Sean

Instead, language should provide some hookable callback (like onOutOfMemoryError()) which is called when memory limit is reached so that program may free some unused memory (which is held by user since it is not garbage-collected) and tries to allocate the memory again without failure (return true from callback). User might decide to re-throw some other kind of *exception*, like NotEnoughMemoryException(), to catch and recover, or pass it (return false from callback) which in turn will finally throw OutOfMemoryError().

But one of the best things possible to do is unwind the stack and fall back to a higher position with less state. A function cannot do that, an exception can.

You can do that, of course, just don't handle the onOutOfMemory custom callback (per my proposal).
 Why do you guys want to avoid exceptions in one of the few cases when 
 they are exactly, but exactly what the doctor prescribed?

 Andrei

My concern is to avoid program flow interrupt and fall-back to some recovery code if possible. One of such cases is OutOfMemoryException. For example, I recieve some network message. An object is constructed and about to be inserted into the message list. Imagine that an OutOfMemoryException is thrown during the insertion. It is quite hard (if possible) and not generally disirable to revert network state: I have to emulate that message is not recieved yet so that I get it later (at a second attempt, after OutOfMemory exception is processed and some memory freed), etc. Besides, where would you put the catch(OutOfMemoryError) code? Far from the exception source point, most likely, which is even worse for recovery. The solution I would prefer is to avoid that situation at all! No memory? Fine, I'll clean this memory pool and that one, too. Try again, please! Still no memory? Then re-throw the exception so that upper forces handle the situation. I don't say that exception recovery is not needed - of course it is! - but I prefer to avoid it if possible. It is just safer. Leave the user unaware that an out of memory error has been occured and recovered from is my best wish.

I understand your motivation. But you can easily implement all of that within client code without changing anything anywhere. Notice that the problem is more general, e.g. if creating a socket fail you might ask the user to plug a cable or start a wireless card etc. Just catch the exception at the appropriate level, take the appropriate measure, and goto RETRY. :o) Andrei
Oct 23 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Denis Koroskin wrote:
 
 I think that OutOfMemoryException should *not* be recoverable. Instead, 
 language should provide some hookable callback (like 
 onOutOfMemoryError()) which is called when memory limit is reached so 
 that program may free some unused memory (which is held by user since it 
 is not garbage-collected) and tries to allocate the memory again without 
 failure (return true from callback). User might decide to re-throw some 
 other kind of *exception*, like NotEnoughMemoryException(), to catch and 
 recover, or pass it (return false from callback) which in turn will 
 finally throw OutOfMemoryError().

This is a fair point, but how does one implement this safely? Let's say for the sake of argument that onOutOfMemoryError() can be hooked by the user and may try to recover. Now: auto x = new int[BIG_NUMBER]; Let's say that gc_malloc() is implemented like so: void* gc_malloc( size_t sz ) { void* ptr; do { ptr = doMalloc(sz); if( ptr is null ) onOutOfMemoryError(); } while( ptr is null ); return ptr; } Now let's assume that the first attempted allocation fails and onOutOfMemoryError() frees some memory rather than throwing so the allocation is attempted again. But BIG_NUMBER is so darn big that the allocation fails again. And once again onOutOfMemoryError() tries to free some memory and returns instead of throwing. Is there any way to structure the recovery mechanism to avoid this situation given that onOutOfMemoryError() has no idea that it's being called in such a loop? gc_malloc() could certainly give up and throw after a certain number of failed attempts, but putting the onus on the caller of onOutOfMemoryError() to deal with this situation is not reasonable in my opinion. Sean
Oct 23 2008
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Sean Kelly wrote:
 Denis Koroskin wrote:
 I think that OutOfMemoryException should *not* be recoverable. 
 Instead, language should provide some hookable callback (like 
 onOutOfMemoryError()) which is called when memory limit is reached so 
 that program may free some unused memory (which is held by user since 
 it is not garbage-collected) and tries to allocate the memory again 
 without failure (return true from callback). User might decide to 
 re-throw some other kind of *exception*, like 
 NotEnoughMemoryException(), to catch and recover, or pass it (return 
 false from callback) which in turn will finally throw OutOfMemoryError().

This is a fair point, but how does one implement this safely? Let's say for the sake of argument that onOutOfMemoryError() can be hooked by the user and may try to recover. Now: auto x = new int[BIG_NUMBER]; Let's say that gc_malloc() is implemented like so: void* gc_malloc( size_t sz ) { void* ptr; do { ptr = doMalloc(sz); if( ptr is null ) onOutOfMemoryError(); } while( ptr is null ); return ptr; } Now let's assume that the first attempted allocation fails and onOutOfMemoryError() frees some memory rather than throwing so the allocation is attempted again. But BIG_NUMBER is so darn big that the allocation fails again. And once again onOutOfMemoryError() tries to free some memory and returns instead of throwing. Is there any way to structure the recovery mechanism to avoid this situation given that onOutOfMemoryError() has no idea that it's being called in such a loop? gc_malloc() could certainly give up and throw after a certain number of failed attempts, but putting the onus on the caller of onOutOfMemoryError() to deal with this situation is not reasonable in my opinion.

Perfectly put. Again: why prevent use of exceptions for the one case that they fit the best? Andrei
Oct 23 2008
prev sibling parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Wed, 22 Oct 2008 19:18:57 -0400,
Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org> wrote:
 Errors represent situations which are typically non-recoverable--program
 logic errors, for example, or situations where data corruption may have
 occurred--while Exceptions represent the bulk of normal execution errors,
 including OutOfMemory conditions.

How, pray tell, is an app supposed to recover from an out-of-memory condition?

In an image editor, a user asks to create a huge image (50k x 50k). You try, run out of memory, and gracefully tell the user that the image was too big and you didn't succeed.
Oct 23 2008
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Sergey Gromov wrote:
 Wed, 22 Oct 2008 19:18:57 -0400,
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org> wrote:
 Errors represent situations which are typically non-recoverable--program
 logic errors, for example, or situations where data corruption may have
 occurred--while Exceptions represent the bulk of normal execution errors,
 including OutOfMemory conditions.


In an image editor, a user asks to create a huge image (50k x 50k). You try, run out of memory, and gracefully tell the user that the image was too big and you didn't succeed.

I could extract many instances of this pattern from my programs. Unfortunately, current bugs in the compiler, phobos, or both lead to sudden death of the application under certain circumstances. I hope one day I'll get around to investigating that. Andrei
Oct 23 2008
parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Thu, 23 Oct 2008 08:45:45 -0500,
Andrei Alexandrescu wrote:
 Sergey Gromov wrote:
 Wed, 22 Oct 2008 19:18:57 -0400,
 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org> wrote:
 Errors represent situations which are typically non-recoverable--program
 logic errors, for example, or situations where data corruption may have
 occurred--while Exceptions represent the bulk of normal execution errors,
 including OutOfMemory conditions.


In an image editor, a user asks to create a huge image (50k x 50k). You try, run out of memory, and gracefully tell the user that the image was too big and you didn't succeed.

I could extract many instances of this pattern from my programs. Unfortunately, current bugs in the compiler, phobos, or both lead to sudden death of the application under certain circumstances. I hope one day I'll get around to investigating that.

I've noticed that failed new sometimes simply returned null instead of throwing an exception. I remember it happened in a 3-line piece of test code.
Oct 23 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
Sergey Gromov wrote:
 
 I've noticed that failed new sometimes simply returned null instead of 
 throwing an exception.  I remember it happened in a 3-line piece of test 
 code.

I think I've corrected all these in druntime. if I haven't please let me know. Sean
Oct 23 2008
parent Sergey Gromov <snake.scaly gmail.com> writes:
Thu, 23 Oct 2008 08:30:31 -0700,
Sean Kelly wrote:
 Sergey Gromov wrote:
 
 I've noticed that failed new sometimes simply returned null instead of 
 throwing an exception.  I remember it happened in a 3-line piece of test 
 code.

I think I've corrected all these in druntime. if I haven't please let me know.

I wasn't using druntime nor Tango when I stumbled upon that. I'm glad to hear that those issues were addressed.
Oct 23 2008
prev sibling next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Sean Kelly wrote:
 Denis Koroskin wrote:
 On Wed, 22 Oct 2008 16:22:02 +0400, Jarrett Billingsley 
 <jarrett.billingsley gmail.com> wrote:

 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

Agreed. BTW, why it is not an Error but Exception?

The Error class was created shortly before release and I didn't get around to reclassifying the exceptions in druntime. From memory though, I think that OutOfMemoryException and UtfException should remain as-is, but the remaining exceptions should probably be errors. Any objections? And as for ArrayBoundsException... how about IndexOutOfBoundsError. It's long, but probably the most self-explanatory. Also, any value in retaining ArrayBoundsError and having it subclass this? I'd think not, but figured I'd ask anyway. Sean

Ah NOOOOO! Please don't make an out of memory catchable with a plain catch(Exception) .... In most programs... pretty much every non-trivial desktop application I can think of... an out-of memory state is basically unrecoverable. In the few cases it would need to be, there would need to be significant handling code, and that would have to be at the right location in the program (i.e. when first opening a file), not in the closest catch-all block some intern down the hallway may have thrown in. Out of memory is an Error subclass in Java and C#, so there's precedent there. catch(Exception) shouldn't be used - but it is, quite often, so things that would cause issues that a user could not normally be expected to recover from should be Error subclasses. Indexing I could see being an exception since that's deterministic and the user's fault. So I guess I disagree on both counts ;-P. Although since index errors don't appear in release modes in D, that gives more case for it to be an Error.
Oct 23 2008
parent reply KennyTM~ <kennytm gmail.com> writes:
Robert Fraser wrote:
 Sean Kelly wrote:
 Denis Koroskin wrote:
 On Wed, 22 Oct 2008 16:22:02 +0400, Jarrett Billingsley 
 <jarrett.billingsley gmail.com> wrote:

 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

Agreed. BTW, why it is not an Error but Exception?

The Error class was created shortly before release and I didn't get around to reclassifying the exceptions in druntime. From memory though, I think that OutOfMemoryException and UtfException should remain as-is, but the remaining exceptions should probably be errors. Any objections? And as for ArrayBoundsException... how about IndexOutOfBoundsError. It's long, but probably the most self-explanatory. Also, any value in retaining ArrayBoundsError and having it subclass this? I'd think not, but figured I'd ask anyway. Sean

Ah NOOOOO! Please don't make an out of memory catchable with a plain catch(Exception) .... In most programs... pretty much every non-trivial desktop application I can think of... an out-of memory state is basically unrecoverable. In the few cases it would need to be, there would need to be significant handling code, and that would have to be at the right location in the program (i.e. when first opening a file), not in the closest catch-all block some intern down the hallway may have thrown in. Out of memory is an Error subclass in Java and C#, so there's precedent there. catch(Exception) shouldn't be used - but it is, quite often, so things that would cause issues that a user could not normally be expected to recover from should be Error subclasses. Indexing I could see being an exception since that's deterministic and the user's fault. So I guess I disagree on both counts ;-P. Although since index errors don't appear in release modes in D, that gives more case for it to be an Error.

Make OutOfMemoryException the own subclass of Throwable? Then we have Throwable Exception Error OutOfMemoryException or we maybe we can have (jokingly) Throwable Exception // Recoverable Error // Should not be recoverable ChallengingException // Recoverable but I won't touch it. OutOfMemoryException // Let programmer to force GC to release memory CPUOnFireException // Let programmer to call local fire station through modem. // etc...
Oct 23 2008
parent Lars Kyllingstad <public kyllingen.NOSPAMnet> writes:
KennyTM~ wrote:
 Robert Fraser wrote:
 Sean Kelly wrote:
 Denis Koroskin wrote:
 On Wed, 22 Oct 2008 16:22:02 +0400, Jarrett Billingsley 
 <jarrett.billingsley gmail.com> wrote:

 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com> 
 wrote:
 I think the name ArrayBoundsException should be changed to a more 
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every 
 class
 that have some sort of index operation and not just for an 
 array/array
 class.

2nded.

Agreed. BTW, why it is not an Error but Exception?

The Error class was created shortly before release and I didn't get around to reclassifying the exceptions in druntime. From memory though, I think that OutOfMemoryException and UtfException should remain as-is, but the remaining exceptions should probably be errors. Any objections? And as for ArrayBoundsException... how about IndexOutOfBoundsError. It's long, but probably the most self-explanatory. Also, any value in retaining ArrayBoundsError and having it subclass this? I'd think not, but figured I'd ask anyway. Sean

Ah NOOOOO! Please don't make an out of memory catchable with a plain catch(Exception) .... In most programs... pretty much every non-trivial desktop application I can think of... an out-of memory state is basically unrecoverable. In the few cases it would need to be, there would need to be significant handling code, and that would have to be at the right location in the program (i.e. when first opening a file), not in the closest catch-all block some intern down the hallway may have thrown in. Out of memory is an Error subclass in Java and C#, so there's precedent there. catch(Exception) shouldn't be used - but it is, quite often, so things that would cause issues that a user could not normally be expected to recover from should be Error subclasses. Indexing I could see being an exception since that's deterministic and the user's fault. So I guess I disagree on both counts ;-P. Although since index errors don't appear in release modes in D, that gives more case for it to be an Error.

Make OutOfMemoryException the own subclass of Throwable? Then we have Throwable Exception Error OutOfMemoryException or we maybe we can have (jokingly) Throwable Exception // Recoverable Error // Should not be recoverable ChallengingException // Recoverable but I won't touch it. OutOfMemoryException // Let programmer to force GC to release memory CPUOnFireException // Let programmer to call local fire station through modem. // etc...

Even though the last suggestion was partially meant as a joke, I think it is actually a good idea. One could have a third hierarchy of exception classes, for exceptions like OutOfMemoryException that one should be able to catch, but that shouldn't be caught by default along with other exceptions. Sort of a "middle ground" between Exception and Error. Not sure about the name "ChallengingException", though. ;) How about SpecialException, CriticalException or something like that? -Lars
Oct 25 2008
prev sibling parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Wed, 22 Oct 2008 12:01:36 -0700,
Sean Kelly wrote:
 And as for ArrayBoundsException... how about IndexOutOfBoundsError. 
 It's long, but probably the most self-explanatory.  Also, any value in 
 retaining ArrayBoundsError and having it subclass this?  I'd think not, 
 but figured I'd ask anyway.

Maybe IndexingError ? There are not necessarily any bounds when you're indexing into an arbitrary collection.
Oct 23 2008
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Sergey Gromov wrote:
 Wed, 22 Oct 2008 12:01:36 -0700,
 Sean Kelly wrote:
 And as for ArrayBoundsException... how about IndexOutOfBoundsError. 
 It's long, but probably the most self-explanatory.  Also, any value in 
 retaining ArrayBoundsError and having it subclass this?  I'd think not, 
 but figured I'd ask anyway.

Maybe IndexingError ? There are not necessarily any bounds when you're indexing into an arbitrary collection.

STL has range_error. I like that because it's rather general. Andrei
Oct 23 2008
parent Sean Kelly <sean invisibleduck.org> writes:
Andrei Alexandrescu wrote:
 Sergey Gromov wrote:
 Wed, 22 Oct 2008 12:01:36 -0700,
 Sean Kelly wrote:
 And as for ArrayBoundsException... how about IndexOutOfBoundsError. 
 It's long, but probably the most self-explanatory.  Also, any value 
 in retaining ArrayBoundsError and having it subclass this?  I'd think 
 not, but figured I'd ask anyway.

Maybe IndexingError ? There are not necessarily any bounds when you're indexing into an arbitrary collection.

STL has range_error. I like that because it's rather general.

The terminology matches D's new range concept anyway, which is a nice perk. Works for me. Sean
Oct 31 2008
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 22 Oct 2008 16:22:02 +0400, Jarrett Billingsley  
<jarrett.billingsley gmail.com> wrote:

 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com>  
 wrote:
 I think the name ArrayBoundsException should be changed to a more  
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every class
 that have some sort of index operation and not just for an array/array
 class.

2nded.

Agreed. BTW, why it is not an Error but Exception?
Oct 22 2008
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 22 Oct 2008 19:06:24 +0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com>  
 wrote:
 I think the name ArrayBoundsException should be changed to a more  
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every  
 class
 that have some sort of index operation and not just for an array/array
 class.


I agree. In fact I wanted to ask you all the following question. What do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

There is sometimes a need to differentiate between a specific exception and a generic one, even though the former or does nothing. typedef Exception MyException; // might be a good compromise try { throw new MyException("reason"); } catch (MyException e) { // catch concrete exception } catch (Exception e) { // catch generic exception } This code currently doesn't work, because compiler thinks that MyException and Exception are of the same type, which is wrong - MyException is kind of a subclass of Exception, as the following sample shows: typedef Exception MyException; void main() { MyException me = new MyException("reason"); Exception e = me; // implicit downcast me = e; // doesn't work, it is an upcast Object o = me; // ICE! :) } Could anyone put it into bugzilla? (I have no access to HTTP currently :()
Oct 22 2008
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 22 Oct 2008 20:25:15 +0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Max Samukha wrote:
 On Wed, 22 Oct 2008 10:06:24 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 6:49 AM, Jacob Carlborg <doobnet gmail.com>  
 wrote:
 I think the name ArrayBoundsException should be changed to a more  
 general
 name like BoundsException, OutOfBoundsException or
 IndexOutOfBoundsException. Then you can use the exception in every  
 class
 that have some sort of index operation and not just for an  
 array/array
 class.


do you think about the current exception hierarchy in phobos? I think it is terrible. Each module in std you open, the first piece of code to be seen is the "class ThisModuleNameException" definition. In many (most?) cases the module-specific exception does absolutely nothing in addition to its base class. The putative reader (including me) tends to scroll non-critically over that passage without even blinking, mumbling in a trance - of course, yes, each module should define at least one exception type. Until one day when you stop scrolling and say, wait a minute. This all is repetition. And there are alternatives to catching by type - you can catch the base type and consult a field. And in fact I don't remember seeing code that depends on exceptions thrown from different modules having different types. There's something wrong here! I think most exception classes in phobos should be yanked if it's possible for their functionality (often nil) to be moved in the Exception base class. The module name should be a member. If someone needs to deal with an exception thrown from a specific module, they can always inspect the field. We don't need a huge hierarchy for that. Andrei

mixins and ordinary template instances should be treated differently: modue a; template Foo() { void Foo() { throw new Exception; } } ---- module b; alias Foo!() foo; // Exception's module should probably be 'a' mixin Foo; // Exception's module is 'b'?

That's a good point. By the way, where is Don's code to get the name of the current module? Andrei

http://www.dsource.org/projects/meta/browser/trunk/meta/NameOf.d ?
Oct 22 2008
prev sibling next sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org> wrote:
 Errors represent situations which are typically non-recoverable--program
 logic errors, for example, or situations where data corruption may have
 occurred--while Exceptions represent the bulk of normal execution errors,
 including OutOfMemory conditions.

How, pray tell, is an app supposed to recover from an out-of-memory condition?
Oct 22 2008
prev sibling next sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Wed, Oct 22, 2008 at 8:02 PM, Sean Kelly <sean invisibleduck.org> wrote:
 For manual recovery, consider an app that does a great deal of internal
 caching.  On an OutOfMemory condition the app could clear its caches and
  then retry the operation.  This is probably a bad example, but I think the
 general idea of trapping and recovering from such a state is potentially
 valid.

I think that's probably a valid thing to try, and considered it after posting. However, without language support for restarting code at the point of the 'throw' it seems like it wouldn't be all that useful.
Oct 22 2008
prev sibling next sibling parent "Bill Baxter" <wbaxter gmail.com> writes:
On Thu, Oct 23, 2008 at 9:11 AM, Jarrett Billingsley
<jarrett.billingsley gmail.com> wrote:
 On Wed, Oct 22, 2008 at 8:02 PM, Sean Kelly <sean invisibleduck.org> wrote:
 For manual recovery, consider an app that does a great deal of internal
 caching.  On an OutOfMemory condition the app could clear its caches and
  then retry the operation.  This is probably a bad example, but I think the
 general idea of trapping and recovering from such a state is potentially
 valid.

I think that's probably a valid thing to try, and considered it after posting. However, without language support for restarting code at the point of the 'throw' it seems like it wouldn't be all that useful.

I think a more common recoverable situation would be an app where user requests opening up a huge image. The app tries to allocate space for the huge image and fails with OutOfMemory. So the app then gives up on creating that huge image and reports to the user "Can't do that. Please buy me some more RAM or turn on some Virtual Memory." But there's still plenty of memory for working on the images that are already loaded. It shouldn't be fatal. --bb
Oct 22 2008
prev sibling next sibling parent Jesse Phillips <jessekphillips gmail.com> writes:
On Wed, 22 Oct 2008 17:02:22 -0700, Sean Kelly wrote:

 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org>
 wrote:
 Errors represent situations which are typically
 non-recoverable--program logic errors, for example, or situations
 where data corruption may have occurred--while Exceptions represent
 the bulk of normal execution errors, including OutOfMemory conditions.

How, pray tell, is an app supposed to recover from an out-of-memory condition?

By releasing dynamically allocated memory. I'd expect some to be released automatically as the stack is unrolled to the catch point anyway. For example: void main() { try { fn(); } catch( Exception e ) {} int[] x = new int[16384]; } void fn() { int[] x = new int[16384]; fn(); } Eventually this app will run out of memory (hopefully before it runs out of stack space) and an OutOfMemoryException will be thrown. As the stack is unwound, all valid references to this memory will be released. So the allocation in main() should trigger a collection which frees up all the now-unreferenced memory, thus allowing the allocation in main() to succeed. For manual recovery, consider an app that does a great deal of internal caching. On an OutOfMemory condition the app could clear its caches and then retry the operation. This is probably a bad example, but I think the general idea of trapping and recovering from such a state is potentially valid. Sean

I think a good reason for keeping it an exception (ie recoverable) is that out of memory may not be the fault of the program. A completely correct program can be given an out of memory error, especially if another program (like your example) eats it up, would you want your whole system to come to an end?
Oct 22 2008
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 23 Oct 2008 04:02:22 +0400, Sean Kelly <sean invisibleduck.org>  
wrote:

 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org>  
 wrote:
 Errors represent situations which are typically  
 non-recoverable--program
 logic errors, for example, or situations where data corruption may have
 occurred--while Exceptions represent the bulk of normal execution  
 errors,
 including OutOfMemory conditions.

condition?

By releasing dynamically allocated memory. I'd expect some to be released automatically as the stack is unrolled to the catch point anyway. For example: void main() { try { fn(); } catch( Exception e ) {} int[] x = new int[16384]; } void fn() { int[] x = new int[16384]; fn(); } Eventually this app will run out of memory (hopefully before it runs out of stack space) and an OutOfMemoryException will be thrown. As the stack is unwound, all valid references to this memory will be released. So the allocation in main() should trigger a collection which frees up all the now-unreferenced memory, thus allowing the allocation in main() to succeed. For manual recovery, consider an app that does a great deal of internal caching. On an OutOfMemory condition the app could clear its caches and then retry the operation. This is probably a bad example, but I think the general idea of trapping and recovering from such a state is potentially valid. Sean

I think that OutOfMemoryException should *not* be recoverable. Instead, language should provide some hookable callback (like onOutOfMemoryError()) which is called when memory limit is reached so that program may free some unused memory (which is held by user since it is not garbage-collected) and tries to allocate the memory again without failure (return true from callback). User might decide to re-throw some other kind of *exception*, like NotEnoughMemoryException(), to catch and recover, or pass it (return false from callback) which in turn will finally throw OutOfMemoryError().
Oct 23 2008
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 23 Oct 2008 17:47:52 +0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Denis Koroskin wrote:
 On Thu, 23 Oct 2008 04:02:22 +0400, Sean Kelly <sean invisibleduck.org>  
 wrote:

 Jarrett Billingsley wrote:
 On Wed, Oct 22, 2008 at 7:13 PM, Sean Kelly <sean invisibleduck.org>  
 wrote:
 Errors represent situations which are typically  
 non-recoverable--program
 logic errors, for example, or situations where data corruption may  
 have
 occurred--while Exceptions represent the bulk of normal execution  
 errors,
 including OutOfMemory conditions.

condition?

By releasing dynamically allocated memory. I'd expect some to be released automatically as the stack is unrolled to the catch point anyway. For example: void main() { try { fn(); } catch( Exception e ) {} int[] x = new int[16384]; } void fn() { int[] x = new int[16384]; fn(); } Eventually this app will run out of memory (hopefully before it runs out of stack space) and an OutOfMemoryException will be thrown. As the stack is unwound, all valid references to this memory will be released. So the allocation in main() should trigger a collection which frees up all the now-unreferenced memory, thus allowing the allocation in main() to succeed. For manual recovery, consider an app that does a great deal of internal caching. On an OutOfMemory condition the app could clear its caches and then retry the operation. This is probably a bad example, but I think the general idea of trapping and recovering from such a state is potentially valid. Sean

Instead, language should provide some hookable callback (like onOutOfMemoryError()) which is called when memory limit is reached so that program may free some unused memory (which is held by user since it is not garbage-collected) and tries to allocate the memory again without failure (return true from callback). User might decide to re-throw some other kind of *exception*, like NotEnoughMemoryException(), to catch and recover, or pass it (return false from callback) which in turn will finally throw OutOfMemoryError().

But one of the best things possible to do is unwind the stack and fall back to a higher position with less state. A function cannot do that, an exception can.

You can do that, of course, just don't handle the onOutOfMemory custom callback (per my proposal).
 Why do you guys want to avoid exceptions in one of the few cases when  
 they are exactly, but exactly what the doctor prescribed?

 Andrei

My concern is to avoid program flow interrupt and fall-back to some recovery code if possible. One of such cases is OutOfMemoryException. For example, I recieve some network message. An object is constructed and about to be inserted into the message list. Imagine that an OutOfMemoryException is thrown during the insertion. It is quite hard (if possible) and not generally disirable to revert network state: I have to emulate that message is not recieved yet so that I get it later (at a second attempt, after OutOfMemory exception is processed and some memory freed), etc. Besides, where would you put the catch(OutOfMemoryError) code? Far from the exception source point, most likely, which is even worse for recovery. The solution I would prefer is to avoid that situation at all! No memory? Fine, I'll clean this memory pool and that one, too. Try again, please! Still no memory? Then re-throw the exception so that upper forces handle the situation. I don't say that exception recovery is not needed - of course it is! - but I prefer to avoid it if possible. It is just safer. Leave the user unaware that an out of memory error has been occured and recovered from is my best wish.
Oct 23 2008
prev sibling next sibling parent "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Oct 24, 2008 at 4:08 AM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Andrei Alexandrescu wrote:
 Sean Kelly wrote:
 Andrei Alexandrescu wrote:
 Robert Fraser wrote:
 Option B:
 ---------
 try
 {
    new Socket(30587);
 }
 catch(Exception e)
 {
    if(e.type == ExceptionType.Socket)
        printf("Could not open socket\n");
    else
        throw e;
 }

I think you'd be hard-pressed to justify the "if" inside the second example. You couldn't create a Socket, period. It doesn't matter where exactly the exception was generated from. That's one thing about large exception hierarchies: everybody can come with cute examples on how they could be useful. As soon as the rubber hits the road, however, differentiating exceptions by type becomes useless.

It may be different in a user application, but in services it's fairly common to have specialized code for handling different exception types. And more importantly, it's common to want different exception types to propagate to different levels for handling. Sure, one could use a generic exception handler at each level that rethrows if the detected type isn't one that handler cares about but why do this when filtering on type is a language feature? For example, let's say I have a network service that's backed by a SQL database. My main program loop may look something like this: bool connected = false; while( true ) { try { while( true ) { auto r = acceptRequest(); scope(failure) r.tellFailed(); if( !connected ) connectToDB(); handleRequest( r ); } } catch( SqlException e ) { connected = false; log( e ); } catch( Exception e ) { log( e ); } } ... void handleRequest( Request r ) { scope(failure) r.tellFailed( "General error" ); try { // process r } catch( AuthException e ) { r.tellFailed( "Authentication failure" ); } catch( ValidationException e ) { r.tellFailed( "Invalid request format" ); } } Being able to trap specific types of exceptions makes this code cleaner and more succinct than it would be otherwise. If this weren't possible I'd have to trap, check, and rethrow certain exceptions at different levels to ensure that the proper handler saw them.

Thanks for fueling my argument. There's duplication in code examples, as in many other examples I've seen in favor of by-type handling. First example: catch( Exception e ) { if (e.origin = "sql") connected = false; log( e ); } Less code and no duplication. Second example is even starker: catch( AuthException e ) { r.tellFailed( e.toString ); } Clearly the need is to factor in the message to print in the exception, at least in this case and many like it. Andrei

By the way, this each-exception-has-its-type crap is my #2 pet peeve after "Follow carefully my pocket watch... OO is good for everything... OO is good for everything... to use, inherit... to use, inherit..."

Interesting point. The whole catch(A){} catch(B){} catch(C){} thing is basically if-then-else on very similar types, which is exactly what the OO crowd says you should try to avoid in any other situation. You should be using polymorphism! But ok, types are good for one thing, and that's ensuring global uniqueness. That seems to be the real point of the billion exception types, to give them unique identifiers that the compiler can check. You can give your exceptions a typecode or a string identifier, like your origin=="sql", but then the compiler won't tell you if your type is unique. And it won't tell you there's a problem if you mistakenly type origin=="SQL" instead of "sql". I think it boils down to a kind of static typing vs dynamic typing argument. --bb
Oct 23 2008
prev sibling next sibling parent "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Oct 24, 2008 at 6:41 AM, Sergey Gromov <snake.scaly gmail.com> wrote:
 Thu, 23 Oct 2008 14:44:46 -0500,
 Andrei Alexandrescu wrote:
 Sorry, I meant to catch Exception. My point was, if I want to print an
 informative message, the exception should be able to provide it without
 having to encode it in its type.

It's all nice and simple until you want to localize. Then all your 'informative compiler-provided messages' appear as garbage to a non- English-speaking user. They need to be translated somehow. And the translation is likely to be based upon the context, not upon an arbitrary string exception contains.

Just use poedit or whatever to provide localizations of the messages. I don't see how this has bearing on the discussion at all. --bb
Oct 23 2008
prev sibling next sibling parent "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Oct 24, 2008 at 10:42 AM, Robert Fraser
<fraserofthenight gmail.com> wrote:
 Sean Kelly wrote:
 Perhaps I'm simply getting old... when did memory use become irrelevant?
  I grant that making an application exception safe is more difficult if out
 of memory conditions are considered recoverable, but I don't think it's
 tremendously more difficult.

I'm currently studying Computer Engineering at university. I don't think a single programming course I've taken has _mentioned_ running out of memory (next quarter I'm taking Operating Systems, so hopefully that will). One class mentioned memory complexity as a side issue, but never got into it. Even at work, I've never been asked to think about it.

People do still develop for embedded devices with small memory and/or no virtual memory. I'm pretty sure it's still a serious concern if you live in that world. --bb
Oct 23 2008
prev sibling next sibling parent Jesse Phillips <jessekphillips gmail.com> writes:
On Fri, 24 Oct 2008 16:04:53 -0700, Robert Fraser wrote:

 Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 10:42 AM, Robert Fraser
 <fraserofthenight gmail.com> wrote:
 Sean Kelly wrote:
 Perhaps I'm simply getting old... when did memory use become
 irrelevant?
  I grant that making an application exception safe is more difficult
  if out
 of memory conditions are considered recoverable, but I don't think
 it's tremendously more difficult.

think a single programming course I've taken has _mentioned_ running out of memory (next quarter I'm taking Operating Systems, so hopefully that will). One class mentioned memory complexity as a side issue, but never got into it. Even at work, I've never been asked to think about it.

People do still develop for embedded devices with small memory and/or no virtual memory. I'm pretty sure it's still a serious concern if you live in that world. --bb

I'm not saying it doesn't come up in practice; I'm saying developers are trained not to think about it in most cases. And programming to handle a small amount of memory is a different problem than programming to gracefully fail when the program runs out of memory (for example, my program might only use 10k of RAM... but if that 10k isn't there, it might just crash with an error message). The problem with an OutOfMemoryError being treated as an Exception is that if there are many catch(Exception) blocks, an out-of-memory error will propagate logic bugs across the program (since no one is cleaning up the memory, most allocations will fail). So instead of a nice, clean error, the suer will experience weird and frustrating behavior that doesn't mention memory at all.

The problem with it being an error is that the programmer has no way to catch and remain usable, leaving the user blissfully unaware he needs to buy more ram. If there are many catch(Exception)'s around, the programmer needs to rethink what he is doing when creating a stable program. D doesn't force a try or throw of exceptions for this very reason; people usually use the catch(Exception) because they don't know what needs to be caught and don't care but are forced to catch it, not because their program is crashing from an exception (well, that is what I do).
Oct 24 2008
prev sibling next sibling parent Jesse Phillips <jessekphillips gmail.com> writes:
On Sat, 25 Oct 2008 15:45:51 -0700, Robert Fraser wrote:

 Jesse Phillips wrote:
 On Fri, 24 Oct 2008 16:04:53 -0700, Robert Fraser wrote:
 
 Bill Baxter wrote:
 On Fri, Oct 24, 2008 at 10:42 AM, Robert Fraser
 <fraserofthenight gmail.com> wrote:
 Sean Kelly wrote:
 Perhaps I'm simply getting old... when did memory use become
 irrelevant?
  I grant that making an application exception safe is more
  difficult if out
 of memory conditions are considered recoverable, but I don't think
 it's tremendously more difficult.

think a single programming course I've taken has _mentioned_ running out of memory (next quarter I'm taking Operating Systems, so hopefully that will). One class mentioned memory complexity as a side issue, but never got into it. Even at work, I've never been asked to think about it.

no virtual memory. I'm pretty sure it's still a serious concern if you live in that world. --bb

are trained not to think about it in most cases. And programming to handle a small amount of memory is a different problem than programming to gracefully fail when the program runs out of memory (for example, my program might only use 10k of RAM... but if that 10k isn't there, it might just crash with an error message). The problem with an OutOfMemoryError being treated as an Exception is that if there are many catch(Exception) blocks, an out-of-memory error will propagate logic bugs across the program (since no one is cleaning up the memory, most allocations will fail). So instead of a nice, clean error, the suer will experience weird and frustrating behavior that doesn't mention memory at all.

The problem with it being an error is that the programmer has no way to catch and remain usable,

Sure there is: catch(OutOfMemoryError) Just like in Java or .Net. The only difference is that it's not caught by a general catch(Exception)
 leaving the user blissfully unaware he needs to buy more ram. If there
 are many catch(Exception)'s around, the programmer needs to rethink
 what he is doing when creating a stable program.

Probably. But when you have a team of 300 programmers, this is a bit harder to do, and catch(Exception) _is_ a powerful tool for generalized recoverable error handling.
 D doesn't force a try or throw of exceptions for this very reason;
 people usually use the catch(Exception) because they don't know what
 needs to be caught and don't care but are forced to catch it, not
 because their program is crashing from an exception (well, that is what
 I do).

People also use it to say to the user "this didn't work; try something else"? In 99% of cases, this is fine, but when memory is involved, the programmer has a whole lot more to think about and would often want to catch the memory exception at a higher level.

Oops, from past discussions about the difference I somehow got the idea that an Error couldn't be caught. While out of memory still falls under recoverable, I can see why putting greater importance over other exceptions would be good.
Oct 25 2008
prev sibling next sibling parent "Bent Rasmussen" <IncredibleShrinkingSphere Gmail.com> writes:
Agreed.

Either that, or superclasss it.

- Bent

"Jacob Carlborg" <doobnet gmail.com> skrev i meddelelsen 
news:gdn0ft$u2m$1 digitalmars.com...
 I think the name ArrayBoundsException should be changed to a more general 
 name like BoundsException, OutOfBoundsException or 
 IndexOutOfBoundsException. Then you can use the exception in every class 
 that have some sort of index operation and not just for an array/array 
 class. 

Oct 26 2008
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Sat, 01 Nov 2008 01:56:49 +0300, Sean Kelly <sean invisibleduck.org>  
wrote:

 Andrei Alexandrescu wrote:
 Sergey Gromov wrote:
 Wed, 22 Oct 2008 12:01:36 -0700,
 Sean Kelly wrote:
 And as for ArrayBoundsException... how about IndexOutOfBoundsError.  
 It's long, but probably the most self-explanatory.  Also, any value  
 in retaining ArrayBoundsError and having it subclass this?  I'd think  
 not, but figured I'd ask anyway.

Maybe IndexingError ? There are not necessarily any bounds when you're indexing into an arbitrary collection.


The terminology matches D's new range concept anyway, which is a nice perk. Works for me. Sean

I find range_error way too generic. What is range error? Invalid range? OutOfRangeError is more suitable imo. Range!(int) r = ...; // random-access range int t = r[2]; // okay, within range int s = r[100]; // error, our of range
Nov 01 2008