View mode: basic / threaded / horizontal-split · Log in · Help
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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.
> >> 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.
> 
> 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.
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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.
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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;
>>> }
>> 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.

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

Andrei
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
"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;
>>>> }
>>> 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.
>
> 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
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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.
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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.
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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
October 23, 2008
Re: Change the name of ArrayBoundsException in druntime
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.
>>>>  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 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.

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.
1 2 3 4 5 6 7 8
Top | Discussion index | About this forum | D home