Jump to page: 1 2
Thread overview
Exception slipping through the catch block?
Nov 08
helxi
Nov 08
helxi
Nov 08
Alex
Nov 08
Bauss
November 08
How does exception work? I am inside a function that calls a constructor. Inside the constructor, an exception is thrown. However even though I have wrapped the body of the function inside a try/catch block, the program crashes from inside that constructor. Shouldn't the catch block in the function catch the exception?

Picture should clear it up a little bit:
https://i.imgur.com/3zinoZq.png

   // ui.d
   103	        deviceCombo.addOnChanged(delegate void(ComboBoxText _) {
   104	            try {
   105	                device = new Device(deviceCombo.getActiveText()); // <-- call sight
   106	                auto status = sanityCheck(device, fcb.getFilename);
   107	                if (status.pass)
   108	                    triggerHboxRevealer.setRevealChild(true);
   109	                else {
   110	                    deviceCombo.setTooltipText(status.reason);
   111	                    triggerHboxRevealer.setRevealChild(false);
   112	                }
   113	            }
   114	            catch (Exception e) {
   115	                deviceCombo.setTooltipText("Cannot read device");
   116	                triggerHboxRevealer.setRevealChild(false);
   117	            }
   118	        });


    // backend.d
    34	    this(in string lsblkLine) {
    35	        auto lineSplit = lsblkLine.split(" ");
    36	        name = lineSplit.front();
    37	        sizePretty = lineSplit.back();
    38	        foreach (str; lineSplit.dropOne().dropBackOne()) // <-- throws exception
    39	            model ~= str ~ " ";
    40	        summary = format("%s\t%s\t%s", name, model, sizePretty);
    41	    }

// error message
core.exception.AssertError@/usr/include/dlang/dmd/std/range/primitives.d(2340): Assertion failure
----------------
??:? _d_assertp [0x4e81ee29]
/usr/include/dlang/dmd/std/range/primitives.d:2340 pure nothrow @nogc @safe void std.range.primitives.popBack!(immutable(char)[]).popBack(ref immutable(char)[][]) [0x4e5e417e]
/usr/include/dlang/dmd/std/range/package.d:3190 pure nothrow @nogc @safe immutable(char)[][] std.range.dropBackOne!(immutable(char)[][]).dropBackOne(immutable(char)[][]) [0x4e5e41d4]
source/backend.d:38 backend.Device backend.Device.__ctor(const(immutable(char)[])) [0x4e5e8e6d]
source/ui.d:105 void ui.PrimaryWindow.__ctor(gtk.Application.Application).__dgliteral4(gtk.ComboBoxText.ComboBoxText) [0x4e5ea17f]
../../../../.dub/packages/gtk-d-3.8.3/gtk-d/generated/gtkd/gobject/DClosure.d:135 extern (C) void gobject.DClosure.DClosure.d_closure_marshal!(void delegate(gtk.ComboBoxText.ComboBoxText)).d_closure_marshal(gobject.c.types.GClosure*, gobject.c.types.GValue*, uint, gobject.c.types.GValue*, void*, void*) [0x4e7bf095]
??:? g_closure_invoke [0x4f9573d4]
Program exited with code 1
November 08
On Thursday, 8 November 2018 at 15:08:40 UTC, helxi wrote:
> Shouldn't the catch block in the function catch the exception?

You caught Exception, but it throws Error. They have separate inheritance trees.


The common ancestor is actually Throwable, though note that there is no guarantee that Errors actually unwind the stack; with certain compile flags they might just abort the program.
November 08
On Thursday, 8 November 2018 at 15:41:11 UTC, Adam D. Ruppe wrote:
> On Thursday, 8 November 2018 at 15:08:40 UTC, helxi wrote:
>> Shouldn't the catch block in the function catch the exception?
>
> You caught Exception, but it throws Error. They have separate inheritance trees.
>
>
> The common ancestor is actually Throwable, though note that there is no guarantee that Errors actually unwind the stack; with certain compile flags they might just abort the program.

Thanks.

Although it's pretty frustrating, isn't it? Now not only I have to think about catching exceptions but also about Errors, and have no guarantee that I have everything under control.
November 08
On Thursday, 8 November 2018 at 15:50:38 UTC, helxi wrote:
>
> Thanks.
>
> Although it's pretty frustrating, isn't it? Now not only I have to think about catching exceptions but also about Errors, and have no guarantee that I have everything under control.

Isn't it rather the case, that you have to think about errors while developing? ;)
November 08
On Thursday, 8 November 2018 at 15:50:38 UTC, helxi wrote:
> On Thursday, 8 November 2018 at 15:41:11 UTC, Adam D. Ruppe wrote:
>> On Thursday, 8 November 2018 at 15:08:40 UTC, helxi wrote:
>>> Shouldn't the catch block in the function catch the exception?
>>
>> You caught Exception, but it throws Error. They have separate inheritance trees.
>>
>>
>> The common ancestor is actually Throwable, though note that there is no guarantee that Errors actually unwind the stack; with certain compile flags they might just abort the program.
>
> Thanks.
>
> Although it's pretty frustrating, isn't it? Now not only I have to think about catching exceptions but also about Errors, and have no guarantee that I have everything under control.

Just don't have errors thrown.
November 08
On Thursday, 8 November 2018 at 15:50:38 UTC, helxi wrote:
> On Thursday, 8 November 2018 at 15:41:11 UTC, Adam D. Ruppe wrote:
>> On Thursday, 8 November 2018 at 15:08:40 UTC, helxi wrote:
>>> Shouldn't the catch block in the function catch the exception?
>>
>> You caught Exception, but it throws Error. They have separate inheritance trees.
>>
>>
>> The common ancestor is actually Throwable, though note that there is no guarantee that Errors actually unwind the stack; with certain compile flags they might just abort the program.
>
> Thanks.
>
> Although it's pretty frustrating, isn't it? Now not only I have to think about catching exceptions but also about Errors, and have no guarantee that I have everything under control.

No, you should never catch Errors. They're separate for a reason.
November 08
On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote:
> On Thursday, 8 November 2018 at 15:50:38 UTC, helxi wrote:

>> Although it's pretty frustrating, isn't it? Now not only I have to think about catching exceptions but also about Errors, and have no guarantee that I have everything under control.
>
> No, you should never catch Errors. They're separate for a reason.

Never say never :) There are legitimate cases for catching an Error or even a Throwable (for example, error propagation in a multi-threaded environment). However, this is not one of such cases.

helxi, an AssertError means there's a problem with your code, it needs to be dealt with by fixing the code, not swallowing the Error.
November 08
On Thursday, November 8, 2018 10:55:45 AM MST Stanislav Blinov via Digitalmars-d-learn wrote:
> On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote:
> > On Thursday, 8 November 2018 at 15:50:38 UTC, helxi wrote:
> >> Although it's pretty frustrating, isn't it? Now not only I have to think about catching exceptions but also about Errors, and have no guarantee that I have everything under control.
> >
> > No, you should never catch Errors. They're separate for a reason.
>
> Never say never :) There are legitimate cases for catching an Error or even a Throwable (for example, error propagation in a multi-threaded environment). However, this is not one of such cases.

Yeah, but basically, the rule of thumb is never. Errors are fatal error conditions which are supposed to terminate the program, and programs should not be trying to recover from them. No one should be attempting to catch them unless they know what they're doing, which honestly, probably isn't going to be very many people for something like this.

Exceptions are for error conditions which are potentially recoverable. Program input or environmental state was bad (e.g. a missing file). They aren't necessarily indicative of bugs in the program, and the program can potentially recover from them and continue to function perfectly fine.

Errors on the other hand, are used to indicate actual bugs in the program or fatal conditions with resources which cannot be recovered from (e.g. the GC running out of memory). They are intended simply to be informative and not to be caught. The stack is not necessarily properly unwound when they are thrown. Full exception handling code is not necessarily even in place when they are thrown, and they can be thrown from nothrow code. By definition, your program is in an invalid state when you catch an Error, and catching an Error to do much of anything is dangerous.

> helxi, an AssertError means there's a problem with your code, it needs to be dealt with by fixing the code, not swallowing the Error.

Specifically, AssertError means that either an assertion failed or something simulating an assertion failed (such as std.exception.assertThrown), so it's something in the code that quite specifically indicates that there's a bug in the code and that a condition that must be true for the code to be in a valid state was false. So, whatever it reported should be tracked down and fixed. In this particular case, it looks like a piece of code called dropBackOne on an empty range.

- Jonathan M Davis



November 08
On Thu, Nov 08, 2018 at 01:28:47PM -0700, Jonathan M Davis via Digitalmars-d-learn wrote:
> On Thursday, November 8, 2018 10:55:45 AM MST Stanislav Blinov via Digitalmars-d-learn wrote:
> > On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote:
[...]
> > > No, you should never catch Errors. They're separate for a reason.
> >
> > Never say never :) There are legitimate cases for catching an Error or even a Throwable (for example, error propagation in a multi-threaded environment). However, this is not one of such cases.
> 
> Yeah, but basically, the rule of thumb is never. Errors are fatal error conditions which are supposed to terminate the program, and programs should not be trying to recover from them. No one should be attempting to catch them unless they know what they're doing, which honestly, probably isn't going to be very many people for something like this.

Recently I ran into a case where catching Throwable makes sense: I have an Android application where the main code interfacing with the Android OS is written in Java, but program logic is written in D, called via JNI.  Since the JVM obviously cannot handle D exceptions, any unhandled D exception that makes it past the JNI boundary would cause the application to crash.  So what I did was to have the JNI interfacing code (on the D side) catch *everything*, i.e., Throwable, marshall the error message into a Java object, then send it via JNI back to the Java code that then displays the error message before aborting the application.  Extremely valuable in debugging, since otherwise I'd have to extract the stacktrace from the system logs, which is a pain.


> Exceptions are for error conditions which are potentially recoverable. Program input or environmental state was bad (e.g. a missing file). They aren't necessarily indicative of bugs in the program, and the program can potentially recover from them and continue to function perfectly fine.
> 
> Errors on the other hand, are used to indicate actual bugs in the program or fatal conditions with resources which cannot be recovered from (e.g. the GC running out of memory). They are intended simply to be informative and not to be caught. The stack is not necessarily properly unwound when they are thrown. Full exception handling code is not necessarily even in place when they are thrown, and they can be thrown from nothrow code. By definition, your program is in an invalid state when you catch an Error, and catching an Error to do much of anything is dangerous.
[...]

Agreed in general.  In my case, though, being able to catch an Error makes it possible to pass on the error message to the Java code and displayed on the screen, instead of the whole thing crashing and burning with no indication of what went wrong.


T

-- 
Bare foot: (n.) A device for locating thumb tacks on the floor.
November 08
On Thursday, November 8, 2018 2:34:38 PM MST H. S. Teoh via Digitalmars-d- learn wrote:
> On Thu, Nov 08, 2018 at 01:28:47PM -0700, Jonathan M Davis via
Digitalmars-d-learn wrote:
> > On Thursday, November 8, 2018 10:55:45 AM MST Stanislav Blinov via
> >
> > Digitalmars-d-learn wrote:
> > > On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote:
> [...]
>
> > > > No, you should never catch Errors. They're separate for a reason.
> > >
> > > Never say never :) There are legitimate cases for catching an Error or even a Throwable (for example, error propagation in a multi-threaded environment). However, this is not one of such cases.
> >
> > Yeah, but basically, the rule of thumb is never. Errors are fatal error conditions which are supposed to terminate the program, and programs should not be trying to recover from them. No one should be attempting to catch them unless they know what they're doing, which honestly, probably isn't going to be very many people for something like this.
>
> Recently I ran into a case where catching Throwable makes sense: I have an Android application where the main code interfacing with the Android OS is written in Java, but program logic is written in D, called via JNI.  Since the JVM obviously cannot handle D exceptions, any unhandled D exception that makes it past the JNI boundary would cause the application to crash.  So what I did was to have the JNI interfacing code (on the D side) catch *everything*, i.e., Throwable, marshall the error message into a Java object, then send it via JNI back to the Java code that then displays the error message before aborting the application.  Extremely valuable in debugging, since otherwise I'd have to extract the stacktrace from the system logs, which is a pain.

You ran into one of the rare cases where it makes sense catch an Error or a Throwable, and you're one of the few people who understands the situation well enough to deal with it properly. The vast majority of D programmers don't. Certainly, anyone who has to ask about the differences between Throwable, Error, and Exception doesn't.

- Jonathan M Davis



« First   ‹ Prev
1 2