digitalmars.D - Collateral Exceptions, Throwable vs Exception
- Andrej Mitrovic <andrej.mitrovich gmail.com> Aug 19 2010
- "Vladimir Panteleev" <vladimir thecybershadow.net> Aug 19 2010
- Sean Kelly <sean invisibleduck.org> Aug 19 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Aug 19 2010
- Stanislav Blinov <stanislav.blinov gmail.com> Aug 19 2010
- Stanislav Blinov <stanislav.blinov gmail.com> Aug 19 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Aug 19 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Aug 19 2010
- Sean Kelly <sean invisibleduck.org> Aug 19 2010
- Sean Kelly <sean invisibleduck.org> Aug 19 2010
- Mike Parker <aldacron gmail.com> Aug 19 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Aug 19 2010
- Mike Parker <aldacron gmail.com> Aug 20 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Aug 19 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Aug 19 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Aug 19 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Aug 19 2010
- Sean Kelly <sean invisibleduck.org> Aug 19 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Aug 19 2010
- "Steven Schveighoffer" <schveiguy yahoo.com> Aug 23 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Aug 19 2010
TDPL code that should work:
class MyException : Exception
{
this(string s)
{
super(s);
}
}
void fun()
{
try
{
throw new Exception("thrown from fun");
}
finally
{
gun(100);
}
}
void gun(int x)
{
try
{
throw new MyException(text("thrown from gun #", x));
}
finally
{
if (x > 1 )
{
gun(x - 1);
}
}
}
import std.stdio, std.conv;
unittest
{
try
{
fun();
}
catch (Exception e)
{
writeln("Primary exception: ", typeid(e), " ", e);
while ((e = e.next) !is null)
{
writeln("Collateral exception: ", typeid(e), " ", e);
}
}
}
void main()
{
}
Errors out:
(49): Error: cannot implicitly convert expression (e.next) of type
object.Throwable to object.Exception
Why would the return type of e.next be Throwable if e is an Exception type?
I've tried casting e.next to type Exception, but that creates an entire mess.
Aug 19 2010
On Thu, 19 Aug 2010 22:43:59 +0300, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:TDPL code that should work:
That reminds me, the code on http://digitalmars.com/d/2.0/windows.html doesn't compile as well. You need to change the signature of the exceptionHandler function (replace Exception with Throwable) for it to compile. -- Best regards, Vladimir mailto:vladimir thecybershadow.net
Aug 19 2010
Andrej Mitrovic Wrote:TDPL code that should work:
Errors out: (49): Error: cannot implicitly convert expression (e.next) of type object.Throwable to object.Exception Why would the return type of e.next be Throwable if e is an Exception type?
Because e.next is a Throwable reference inherited from Throwable: class Throwable { Throwable next; } class Error : Throwable {} class Exception : Throwable {} Because collateral exceptions could be both Errors and Exceptions, I don't think the sample code can work exactly as written.
Aug 19 2010
--001636283bde3c1184048e32fc37
Content-Type: text/plain; charset=ISO-8859-1
Actually, would this be safe to use? :
try
{
fun();
}
catch (Exception e)
{
writeln("Primary exception: ", typeid(e));
while ((e = cast(Exception)e.next) !is null)
{
writeln("Collateral exception: ", typeid(e));
}
}
On Thu, Aug 19, 2010 at 10:18 PM, Andrej Mitrovic <
andrej.mitrovich gmail.com> wrote:
That goes against the statement in TDPL that user code should never catch
Throwable's, unless absolutely necessary. So in case of collateral
exceptions, we are forced to catch Throwable anyway?
On Thu, Aug 19, 2010 at 10:00 PM, Sean Kelly <sean invisibleduck.org>wrote:
Andrej Mitrovic Wrote:
TDPL code that should work:
Errors out:
(49): Error: cannot implicitly convert expression (e.next) of type
Why would the return type of e.next be Throwable if e is an Exception
Because e.next is a Throwable reference inherited from Throwable:
class Throwable {
Throwable next;
}
class Error : Throwable {}
class Exception : Throwable {}
Because collateral exceptions could be both Errors and Exceptions, I don't
think the sample code can work exactly as written.
--001636283bde3c1184048e32fc37
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Actually, would this be safe to use? :<br><br>=A0=A0=A0 try<br>=A0=A0=A0 {<=
br>=A0=A0=A0=A0=A0=A0=A0 fun();<br>=A0=A0=A0 }<br>=A0=A0=A0 catch (Exceptio=
n e)<br>=A0=A0=A0 {<br>=A0=A0=A0=A0=A0=A0=A0 writeln("Primary exceptio=
n: ", typeid(e));<br>=A0=A0=A0=A0=A0=A0=A0 <br>=A0=A0=A0=A0=A0=A0=A0 w=
hile ((e =3D cast(Exception)e.next) !is null)<br>
=A0=A0=A0=A0=A0=A0=A0 {<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 writeln("=
Collateral exception: ", typeid(e));<br>=A0=A0=A0=A0=A0=A0=A0 }=A0 <br=
=A0=A0=A0 }<br><br><br><br><div class=3D"gmail_quote">On Thu, Aug 19, 2010=
j.mitrovich gmail.com">andrej.mitrovich gmail.com</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; borde=
r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">That goes against=
the statement in TDPL that user code should never catch Throwable's, u=
nless absolutely necessary. So in case of collateral exceptions, we are for=
ced to catch Throwable anyway?<div>
<div></div><div class=3D"h5"><br><br><div class=3D"gmail_quote">
On Thu, Aug 19, 2010 at 10:00 PM, Sean Kelly <span dir=3D"ltr"><<a href=
=3D"mailto:sean invisibleduck.org" target=3D"_blank">sean invisibleduck.org=
</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin=
: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-lef=
t: 1ex;">
<div>Andrej Mitrovic Wrote:<br>
<br>
> TDPL code that should work:<br>
</div>...<br>
<div>> Errors out:<br>
> (49): Error: cannot implicitly convert expression (e.next) of type obj=
ect.Throwable to object.Exception<br>
><br>
> Why would the return type of e.next be Throwable if e is an Exception =
type?<br>
<br>
</div>Because e.next is a Throwable reference inherited from Throwable:<br>
<br>
class Throwable {<br>
=A0 =A0Throwable next;<br>
}<br>
<br>
class Error : Throwable {}<br>
class Exception : Throwable {}<br>
<br>
Because collateral exceptions could be both Errors and Exceptions, I don=
9;t think the sample code can work exactly as written.<br>
</blockquote></div><br>
</div></div></blockquote></div><br>
--001636283bde3c1184048e32fc37--
Aug 19 2010
Andrej Mitrovic wrote:Actually, would this be safe to use? : try { fun(); } catch (Exception e) { writeln("Primary exception: ", typeid(e)); while ((e = cast(Exception)e.next) !is null) { writeln("Collateral exception: ", typeid(e)); } }
I'm no expert, but why shouldn't? I'd propose a correction though: while ((e = e.next) !is null) { if (cast(Exception)e) { writeln(/*whatever*/); } }
Aug 19 2010
Andrej Mitrovic wrote:The problem is in the e = e.next assignment, not in the code block below it. On Thu, Aug 19, 2010 at 10:42 PM, Stanislav Blinov <stanislav.blinov gmail.com> wrote:Andrej Mitrovic wrote:Actually, would this be safe to use? : try { fun(); } catch (Exception e) { writeln("Primary exception: ", typeid(e)); while ((e = cast(Exception)e.next) !is null) { writeln("Collateral exception: ", typeid(e)); } }
while ((e = e.next) !is null) { if (cast(Exception)e) { writeln(/*whatever*/); } }
Aug 19 2010
Damn gmail and formatting. I hope that last message wasn't garbled. On Thu, Aug 19, 2010 at 10:25 PM, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:Actually, would this be safe to use? :
Aug 19 2010
On 08/19/2010 03:00 PM, Sean Kelly wrote:Andrej Mitrovic Wrote:TDPL code that should work:
Errors out: (49): Error: cannot implicitly convert expression (e.next) of type object.Throwable to object.Exception Why would the return type of e.next be Throwable if e is an Exception type?
Because e.next is a Throwable reference inherited from Throwable: class Throwable { Throwable next; } class Error : Throwable {} class Exception : Throwable {} Because collateral exceptions could be both Errors and Exceptions, I don't think the sample code can work exactly as written.
Sean's right. And thanks Sean and Walter for implementing the exceptions spec properly, I believe it's very important to the success of D. Andrej... sounds like another errata entry, please :o). Andrei
Aug 19 2010
Andrej Mitrovic Wrote:Yes, I've added it as Throwable. But there's one more problem with your code, this: catch (Throwable e) // have to use Throwable for collateral exceptions // or maybe use a cast like below { writeln("Primary exception: ", typeid(e), " ", e); while ((e = e.next) !is null) { writeln("Collateral exception: ", typeid(e), " ", e); } } Will output ~5000 lines of "Exception .." stuff. Oh and in the book it looks like you're counting from 100 to 1 (for the throws from gun), which makes sense. Yet I'm getting back output from 1 to 100. Not sure what's going on there..
Are these stack trace lines or actual distinct exceptions?
Aug 19 2010
The .next property is to allow chaining. However, it may be that the current behavior of toString is incorrect, or that a new function should be added that only returns a string describing the current exception and not the entire chain. Andrej Mitrovic Wrote:I think I found the problem. e contains all the collateral exceptions (in a linked list according to TDPL), and printing out e will print out each and every collateral exception. So if that's the case, there's no point to using that while loop. But if we can't print out only one exception from a linked list, then what is the point of the .next property? This prints out the all the collateral exceptions: try { fun(); } catch (Throwable e) { writeln(e); } On Thu, Aug 19, 2010 at 11:11 PM, Sean Kelly <sean invisibleduck.org> wrote:Andrej Mitrovic Wrote:Yes, I've added it as Throwable. But there's one more problem with your code, this: catch (Throwable e) // have to use Throwable for collateral exceptions // or maybe use a cast like below { writeln("Primary exception: ", typeid(e), " ", e); while ((e = e.next) !is null) { writeln("Collateral exception: ", typeid(e), " ", e); } } Will output ~5000 lines of "Exception .." stuff. Oh and in the book it looks like you're counting from 100 to 1 (for the throws from gun), which makes sense. Yet I'm getting back output from 1 to 100. Not sure what's going on there..
Are these stack trace lines or actual distinct exceptions?
Aug 19 2010
Sean Kelly wrote:The .next property is to allow chaining. However, it may be that the current behavior of toString is incorrect, or that a new function should be added that only returns a string describing the current exception and not the entire chain.
IMO, it should be the opposite. I noticed the current behavior the other day and was surprised. I would expect toString to return only the message from the Throwable I called it on. A concatenated string of messages from the whole chain would be the special case to be separated into a convenience function. Then again, I don't see the convenience function being necessary, as it's trivial to roll your own for the cases when you want it -- which is what I was doing when I discovered the current behavior and, like Andrej, was confronted by a long list of exception messages.
Aug 19 2010
On 08/19/2010 10:14 PM, Mike Parker wrote:Sean Kelly wrote:The .next property is to allow chaining. However, it may be that the current behavior of toString is incorrect, or that a new function should be added that only returns a string describing the current exception and not the entire chain.
IMO, it should be the opposite. I noticed the current behavior the other day and was surprised. I would expect toString to return only the message from the Throwable I called it on. A concatenated string of messages from the whole chain would be the special case to be separated into a convenience function. Then again, I don't see the convenience function being necessary, as it's trivial to roll your own for the cases when you want it -- which is what I was doing when I discovered the current behavior and, like Andrej, was confronted by a long list of exception messages.
My opinion: Throwable should have a property called printingDepth or something. It should default to e.g. 3 (or conservatively at 1) and limit the number of exceptions in a chain formatted in toString(). Andrei
Aug 19 2010
Andrei Alexandrescu wrote:On 08/19/2010 10:14 PM, Mike Parker wrote:Sean Kelly wrote:The .next property is to allow chaining. However, it may be that the current behavior of toString is incorrect, or that a new function should be added that only returns a string describing the current exception and not the entire chain.
IMO, it should be the opposite. I noticed the current behavior the other day and was surprised. I would expect toString to return only the message from the Throwable I called it on. A concatenated string of messages from the whole chain would be the special case to be separated into a convenience function. Then again, I don't see the convenience function being necessary, as it's trivial to roll your own for the cases when you want it -- which is what I was doing when I discovered the current behavior and, like Andrej, was confronted by a long list of exception messages.
My opinion: Throwable should have a property called printingDepth or something. It should default to e.g. 3 (or conservatively at 1) and limit the number of exceptions in a chain formatted in toString(). Andrei
Yes, that's better. +1.
Aug 20 2010
On 08/19/2010 03:45 PM, Andrej Mitrovic wrote:Yes, I've added it as Throwable. But there's one more problem with your code, this: catch (Throwable e) // have to use Throwable for collateral exceptions // or maybe use a cast like below { writeln("Primary exception: ", typeid(e), " ", e); while ((e = e.next) !is null) { writeln("Collateral exception: ", typeid(e), " ", e); } } Will output ~5000 lines of "Exception .." stuff. Oh and in the book it looks like you're counting from 100 to 1 (for the throws from gun), which makes sense. Yet I'm getting back output from 1 to 100. Not sure what's going on there..
The reverse ordering seems to be a bug in the implementation. Andrei
Aug 19 2010
On 08/19/2010 03:18 PM, Andrej Mitrovic wrote:That goes against the statement in TDPL that user code should never catch Throwable's, unless absolutely necessary. So in case of collateral exceptions, we are forced to catch Throwable anyway?
Indirectly, yes (I'm not positive about this detail though): if an Exception is in flight but a Throwable was produced as collateral damage, the Throwable won't disobey normal scoping rules etc. so it won't be "special" anymore. Andrei
Aug 19 2010
Yes, I've added it as Throwable. But there's one more problem with
your code, this:
catch (Throwable e) // have to use Throwable for collateral exceptions
// or maybe use a cast like below
{
writeln("Primary exception: ", typeid(e), " ", e);
while ((e =3D e.next) !is null)
{
writeln("Collateral exception: ", typeid(e), " ", e);
}
}
Will output ~5000 lines of "Exception .." stuff. Oh and in the book it
looks like you're counting from 100 to 1 (for the throws from gun),
which makes sense. Yet I'm getting back output from 1 to 100. Not sure
what's going on there..
On Thu, Aug 19, 2010 at 10:32 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
On 08/19/2010 03:00 PM, Sean Kelly wrote:
Andrej Mitrovic Wrote:
TDPL code that should work:
...
Errors out:
(49): Error: cannot implicitly convert expression (e.next) of type
object.Throwable to object.Exception
Why would the return type of e.next be Throwable if e is an Exception
type?
Because e.next is a Throwable reference inherited from Throwable:
class Throwable {
=A0 =A0 Throwable next;
}
class Error : Throwable {}
class Exception : Throwable {}
Because collateral exceptions could be both Errors and Exceptions, I don=
think the sample code can work exactly as written.
Sean's right. And thanks Sean and Walter for implementing the exceptions
spec properly, I believe it's very important to the success of D.
Andrej... sounds like another errata entry, please :o).
Andrei
Aug 19 2010
The problem is in the e =3D e.next assignment, not in the code block below = it. On Thu, Aug 19, 2010 at 10:42 PM, Stanislav Blinov <stanislav.blinov gmail.com> wrote:Andrej Mitrovic wrote:Actually, would this be safe to use? : =A0 =A0try =A0 =A0{ =A0 =A0 =A0 =A0fun(); =A0 =A0} =A0 =A0catch (Exception e) =A0 =A0{ =A0 =A0 =A0 =A0writeln("Primary exception: ", typeid(e)); =A0 =A0 =A0 =A0 =A0 =A0 =A0 while ((e =3D cast(Exception)e.next) !is nul=
=A0 =A0 =A0 =A0{ =A0 =A0 =A0 =A0 =A0 =A0writeln("Collateral exception: ", typeid(e)); =A0 =A0 =A0 =A0} =A0 =A0 }
I'm no expert, but why shouldn't? I'd propose a correction though: while ((e =3D e.next) !is null) { =A0 =A0if (cast(Exception)e) =A0 =A0{ =A0 =A0 =A0 =A0writeln(/*whatever*/); =A0 =A0} }
Aug 19 2010
Andrej Mitrovic Wrote:That goes against the statement in TDPL that user code should never catch Throwable's, unless absolutely necessary. So in case of collateral exceptions, we are forced to catch Throwable anyway?
You should avoid explicitly catching Throwable, but I can see what you're getting at: if a collateral exception is an Error then it should not be ignored. You could always do something like this: catch (Exception e) { for (Throwable t = e; t; t = t.next) { if (cast(Error) t) throw t; // collateral damage critical! writeln(t); } }
Aug 19 2010
I think I found the problem. e contains all the collateral exceptions
(in a linked list according to TDPL), and printing out e will print
out each and every collateral exception.
So if that's the case, there's no point to using that while loop. But
if we can't print out only one exception from a linked list, then what
is the point of the .next property?
This prints out the all the collateral exceptions:
try
{
fun();
}
catch (Throwable e)
{
writeln(e);
}
On Thu, Aug 19, 2010 at 11:11 PM, Sean Kelly <sean invisibleduck.org> wrote=
:
Andrej Mitrovic Wrote:
Yes, I've added it as Throwable. But there's one more problem with
your code, this:
catch (Throwable e) =A0 =A0 // have to use Throwable for collateral exce=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 // or maybe use =
=A0 =A0 {
=A0 =A0 =A0 =A0 writeln("Primary exception: ", typeid(e), " ", e);
=A0 =A0 =A0 =A0 while ((e =3D e.next) !is null)
=A0 =A0 =A0 =A0 {
=A0 =A0 =A0 =A0 =A0 =A0 writeln("Collateral exception: ", typeid(e), " "=
=A0 =A0 =A0 =A0 }
=A0 =A0 }
Will output ~5000 lines of "Exception .." stuff. Oh and in the book it
looks like you're counting from 100 to 1 (for the throws from gun),
which makes sense. Yet I'm getting back output from 1 to 100. Not sure
what's going on there..
Are these stack trace lines or actual distinct exceptions?
Aug 19 2010
On Thu, 19 Aug 2010 18:48:15 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 08/19/2010 03:45 PM, Andrej Mitrovic wrote:Yes, I've added it as Throwable. But there's one more problem with your code, this: catch (Throwable e) // have to use Throwable for collateral exceptions // or maybe use a cast like below { writeln("Primary exception: ", typeid(e), " ", e); while ((e = e.next) !is null) { writeln("Collateral exception: ", typeid(e), " ", e); } } Will output ~5000 lines of "Exception .." stuff. Oh and in the book it looks like you're counting from 100 to 1 (for the throws from gun), which makes sense. Yet I'm getting back output from 1 to 100. Not sure what's going on there..
The reverse ordering seems to be a bug in the implementation.
Don't have the book in front of me, but it is important that collateral exceptions be ordered in reverse order of insertion, otherwise, adding a collateral exception involves a linear search to the end of the linked list. -Steve
Aug 23 2010
--001636b14d6c7cbcee048e32e20e Content-Type: text/plain; charset=ISO-8859-1 That goes against the statement in TDPL that user code should never catch Throwable's, unless absolutely necessary. So in case of collateral exceptions, we are forced to catch Throwable anyway? On Thu, Aug 19, 2010 at 10:00 PM, Sean Kelly <sean invisibleduck.org> wrote:Andrej Mitrovic Wrote:TDPL code that should work:
Errors out: (49): Error: cannot implicitly convert expression (e.next) of type
Why would the return type of e.next be Throwable if e is an Exception
Because e.next is a Throwable reference inherited from Throwable: class Throwable { Throwable next; } class Error : Throwable {} class Exception : Throwable {} Because collateral exceptions could be both Errors and Exceptions, I don't think the sample code can work exactly as written.
--001636b14d6c7cbcee048e32e20e Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable That goes against the statement in TDPL that user code should never catch T= hrowable's, unless absolutely necessary. So in case of collateral excep= tions, we are forced to catch Throwable anyway?<br><br><div class=3D"gmail_= quote"> On Thu, Aug 19, 2010 at 10:00 PM, Sean Kelly <span dir=3D"ltr"><<a href= =3D"mailto:sean invisibleduck.org">sean invisibleduck.org</a>></span> wr= ote:<br><blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8e= x; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> <div class=3D"im">Andrej Mitrovic Wrote:<br> <br> > TDPL code that should work:<br> </div>...<br> <div class=3D"im">> Errors out:<br> > (49): Error: cannot implicitly convert expression (e.next) of type obj= ect.Throwable to object.Exception<br> ><br> > Why would the return type of e.next be Throwable if e is an Exception = type?<br> <br> </div>Because e.next is a Throwable reference inherited from Throwable:<br> <br> class Throwable {<br> =A0 =A0Throwable next;<br> }<br> <br> class Error : Throwable {}<br> class Exception : Throwable {}<br> <br> Because collateral exceptions could be both Errors and Exceptions, I don= 9;t think the sample code can work exactly as written.<br> </blockquote></div><br> --001636b14d6c7cbcee048e32e20e--
Aug 19 2010









"Vladimir Panteleev" <vladimir thecybershadow.net> 