www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Rethrow an exception like in C++?

reply "Rob T" <alanb ucora.com> writes:
In C++, I rethrow an exception without explicitly catching it

catch(...)
{
    throw;
}

Anyone know of a way to do the same thing in D?

catch
{
    // rethrow?

}

--rt
Mar 07 2013
next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/8/13, Rob T <alanb ucora.com> wrote:
 In C++, I rethrow an exception without explicitly catching it

 catch(...)
 {
     throw;
 }

 Anyone know of a way to do the same thing in D?

 catch
 {
     // rethrow?

 }
The only way: try { } catch (Exception ex) { throw ex; } Or use Error or Throwable if really necessary, however you shouldn't really catch those in normal code.
Mar 07 2013
parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 01:56:45 UTC, Andrej Mitrovic wrote:
 On 3/8/13, Rob T <alanb ucora.com> wrote:
 In C++, I rethrow an exception without explicitly catching it

 catch(...)
 {
     throw;
 }

 Anyone know of a way to do the same thing in D?

 catch
 {
     // rethrow?

 }
The only way: try { } catch (Exception ex) { throw ex; } Or use Error or Throwable if really necessary, however you shouldn't really catch those in normal code.
That's very unfortunate, and should be corrected, because it means that you cannot easily catch multiple derived Exception types and rethrow the same derived type. Instead you have to explicitly catch all derived types and rethrow them individually, but that's simply not practical, so you end up catching only the base exception (Throwable?) and rethrow it, but you lose the derived type in the process. --rt
Mar 07 2013
next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Friday, 8 March 2013 at 05:46:48 UTC, Rob T wrote:
 That's very unfortunate, and should be corrected, because it 
 means that you cannot easily catch multiple derived Exception 
 types and rethrow the same derived type. Instead you have to 
 explicitly catch all derived types and rethrow them 
 individually, but that's simply not practical, so you end up 
 catching only the base exception (Throwable?) and rethrow it, 
 but you lose the derived type in the process.

 --rt
Actually no. class myException1 : Exception { this() { super("1"); } } class myException2 : Exception { this() { super("2"); } } void foo(bool val) { if (val) throw new myException1; else throw new myException2; } void bar(bool val) { try { foo(val); } catch (Exception e) { if (typeid(e) == typeid(myException1)) throw e; // may be downcasted, if necessary // to work with specific fields } } void main() { try { bar(true); } catch (myException1 e) {} bar(false); }
Mar 07 2013
next sibling parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 06:05:02 UTC, Maxim Fomin wrote:
 Actually no.

 class myException1 : Exception { this() { super("1"); } }
 class myException2 : Exception { this() { super("2"); } }
[...] Thanks! That solves 99% of my problem. I wasn't aware that I could check the derived type from a base class reference like that. The only remaining 1% is that I have a bit more boiler plate code for my catch, because I still have to always explicitly catch something otherwise I cannot )for example) write a function to get the exception and perform work on it and then rethrow. Instead I have to catch( Exception E ) { throw dostuff( E ); } in C++ I could do simply this catch(...) { // do stuff could get the exception on its own throw dostuff(); } Seems trivial, but over hundreds of functions it becomes more of a significant productivity issue. I can live with it, but I still think D could use an ability to rethrow whatever was the last exception with having to explicitly catch it. --rt
Mar 07 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 08:08:48 Rob T wrote:
 On Friday, 8 March 2013 at 06:05:02 UTC, Maxim Fomin wrote:
 Actually no.
 
 class myException1 : Exception { this() { super("1"); } }
 class myException2 : Exception { this() { super("2"); } }
[...] Thanks! That solves 99% of my problem. I wasn't aware that I could check the derived type from a base class reference like that. The only remaining 1% is that I have a bit more boiler plate code for my catch, because I still have to always explicitly catch something otherwise I cannot )for example) write a function to get the exception and perform work on it and then rethrow. Instead I have to catch( Exception E ) { throw dostuff( E ); } in C++ I could do simply this catch(...) { // do stuff could get the exception on its own throw dostuff(); }
Then you can clearly do something here in C++ that I don't understand, because I have absolutely no idea how you could do anything the exception if you did catch(...), because there's no variable to work with. Also, seeing as how the only difference between the two examples is that in the first case, the exception is passed to be thrown and the second it's thrown without its name, I don't see any functional difference between the two. So, I must be missing something here. - Jonathan M Davis
Mar 07 2013
parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 07:58:42 UTC, Jonathan M Davis wrote:
[...]
 Then you can clearly do something here in C++ that I don't 
 understand, because
 I have absolutely no idea how you could do anything the 
 exception if you did
 catch(...), because there's no variable to work with.
Check this out ... In C++ you can do this std::exception Trace() { try { // key item missing from D throw; // <= rethrow last exception } catch( EType1 &E ) { // do stuff return new std::exception( ... } catch( EType2 &E ) { // do different stuff return new std::exception( ... } catch(...) { // unkown type, do something else throw new std::exception( ... } } void Foo() { try { // For example only, I'd never do this! throw 10; } // I don't want to bother with what was // caught because I really don't need to know // so I catch whatever it may be. catch(...) { // I let Trace figure it all out. throw Trace(); } return; } int main() { try { Foo(); } catch( std::exception E ) { std::cout << E.what(); } return 0; } In D, I have to explicitly catch and paste the exception reference to the function, and that is extra work that could be avoided if D could rethrow in a blanket catch block. Eg, catch // I don't care what I caught { // If Trace could rethrow it could figure out what // was thrown and how to deal with it. throw Trace(); } Instead I have to always do this catch( Exception E ) { throw Trace( E ); } That's OK for 20 try catch but specifying catch(Exception E) over and over adds up when you have to write a lot more of those. Copy paste helps, but not always. --rt
Mar 08 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 09:39:12 Rob T wrote:
 That's OK for 20 try catch but specifying catch(Exception E) over
 and over adds up when you have to write a lot more of those. Copy
 paste helps, but not always.
So, the only difference is that C++ is catch(...) { throw trace(); } whereas D is catch(Exception e) { throw trace(e); } If that's the case, I really don't see what the problem is. It's just a few characters difference. - Jonathan M Davis
Mar 08 2013
parent reply "Chris Cain" <clcain uncg.edu> writes:
On Friday, 8 March 2013 at 09:01:14 UTC, Jonathan M Davis wrote:
 If that's the case, I really don't see what the problem is. 
 It's just a few
 characters difference.
To be honest, the way I look at it, D does this _better_. "throw;" looks like magic and it's accessing global (potentially mutable) state to do something. I haven't done much research into C++'s handling of exceptions (and, in particular, this feature), but I'd be _very_ weary of doing that without knowing whether this global state is thread local or shared. If it's shared, you would have some nice heisenbugs pop up if this was used in multithreaded code. Using "catch(Exception E) { throw Trace(E); }" is more explicit to what Trace needs to work and, IMO, a better design.
Mar 08 2013
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 10:07:58 Chris Cain wrote:
 On Friday, 8 March 2013 at 09:01:14 UTC, Jonathan M Davis wrote:
 If that's the case, I really don't see what the problem is.
 It's just a few
 characters difference.
To be honest, the way I look at it, D does this _better_. "throw;" looks like magic and it's accessing global (potentially mutable) state to do something. I haven't done much research into C++'s handling of exceptions (and, in particular, this feature), but I'd be _very_ weary of doing that without knowing whether this global state is thread local or shared. If it's shared, you would have some nice heisenbugs pop up if this was used in multithreaded code. Using "catch(Exception E) { throw Trace(E); }" is more explicit to what Trace needs to work and, IMO, a better design.
I agree. - Jonathan M Davis
Mar 08 2013
prev sibling parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 09:07:59 UTC, Chris Cain wrote:
 On Friday, 8 March 2013 at 09:01:14 UTC, Jonathan M Davis wrote:
 If that's the case, I really don't see what the problem is. 
 It's just a few
 characters difference.
To be honest, the way I look at it, D does this _better_. "throw;" looks like magic and it's accessing global (potentially mutable) state to do something. I haven't done much research into C++'s handling of exceptions (and, in particular, this feature), but I'd be _very_ weary of doing that without knowing whether this global state is thread local or shared. If it's shared, you would have some nice heisenbugs pop up if this was used in multithreaded code. Using "catch(Exception E) { throw Trace(E); }" is more explicit to what Trace needs to work and, IMO, a better design.
The point I'm trying to illustrate is difficult to understand unless you have to personally implement 1000 try/catch statements in your code base. You'll never know how a seemingly trivial item like re-specifying the same pointless catch statement over and over and over again quickly adds up and the frustration knowing that there's a simple solution at hand, but it's not available in what is otherwise a much better language than the one that has the solution. I'm not at all trying to make a case that D's exception handling is somehow inferior to C++. What tends to happen with D is that it's very close to being "really really good" but it is not yet refined to the same degree that a mature language is, so there are always a few items here and there that could be made to work better. Pointing them out is not an attack on D, it's what is necessary to improve the language. I suspect it is simple to implement a safe re-throw in D, it's just hard to see why you would want to use it unless you have the experience of making use of try catch very frequently in a large code base. --rt
Mar 08 2013
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 18:32:43 Rob T wrote:
 The point I'm trying to illustrate is difficult to understand
 unless you have to personally implement 1000 try/catch statements
 in your code base. You'll never know how a seemingly trivial item
 like re-specifying the same pointless catch statement over and
 over and over again quickly adds up and the frustration knowing
 that there's a simple solution at hand, but it's not available in
 what is otherwise a much better language than the one that has
 the solution.
Except that the C++ one is just as pointless. In both cases, you're telling it to catch everything. It's just that syntax is slightly different, because D doesn't allow you to throw without an explicit variable. And it's only a handful of characters difference in length. So, to some of us at least, it seems like you're blowing things out of proportion. And given the lack of clarity in the C++ solution, it comes off as being worse from a technical perspective, regardless of the typing involved. - Jonathan M Davis
Mar 08 2013
parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 18:49:53 UTC, Jonathan M Davis wrote:
 Except that the C++ one is just as pointless. In both cases, 
 you're telling it
 to catch everything. It's just that syntax is slightly 
 different, because D
 doesn't allow you to throw without an explicit variable. And 
 it's only a
 handful of characters difference in length. So, to some of us 
 at least, it
 seems like you're blowing things out of proportion. And given 
 the lack of
 clarity in the C++ solution, it comes off as being worse from a 
 technical
 perspective, regardless of the typing involved.

 - Jonathan M Davis
I don't wish to blow things out of proportion, and will say again that the main objective I was trying to achieve has been met, thanks to the assistance I received in here, so this remaining item is not all that major, it's just an unnecessary repetitive nuisance to me. From a technical stand point, I'm implementing a reusable exception handler or dispatcher (I've seen these two terms used to describe it) which is extremely useful to me, and I would assume to many others. There are examples of this concept implemented in C++ by other programmers, that's how I got the idea. Before I started using an exception handler, my exception handling was very limited and tedious to implement, and I never saw a need to re-throw an exception. There may be other uses for rethrow that I'm not aware of. What my C++ exception handler does not require, is the exception reference passed in as an argument, so that's one of the main differences between what D allows and what C++ allows. In my case every catch statement and function call will be identical, it's slightly more tedious to type in than the C++ version. No big deal for you, but it is annoying for me because I use this form very frequently. If you know of a better way to implement an exception handler in D, then I'd like to know about it. For example I do know that D's system allows you to insert callback functions, but I don't yet know how to make use out of it, so perhaps there's a better way. Any further help or insight on this matter is appreciated. --rt
Mar 08 2013
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 20:16:13 Rob T wrote:
 If you know of a better way to implement an exception handler in
 D, then I'd like to know about it. For example I do know that D's
 system allows you to insert callback functions, but I don't yet
 know how to make use out of it, so perhaps there's a better way.
If all you need to do is do something when an exception is thrown and don't need the exception itself, then just use scope statements: http://dlang.org/statement.html#ScopeGuardStatement scope(failure) doSomethingOnException(); //code that might throw The block inside the scope statement will run when the surrounding scope is exited with an exception. That _really_ cleans up a lot of code that just wants to react to the fact that an exception was thrown and not actually do anything with it. - Jonathan M Davis
Mar 08 2013
parent "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 20:32:23 UTC, Jonathan M Davis wrote:
 On Friday, March 08, 2013 20:16:13 Rob T wrote:
 If you know of a better way to implement an exception handler 
 in
 D, then I'd like to know about it. For example I do know that 
 D's
 system allows you to insert callback functions, but I don't yet
 know how to make use out of it, so perhaps there's a better 
 way.
If all you need to do is do something when an exception is thrown and don't need the exception itself, then just use scope statements: http://dlang.org/statement.html#ScopeGuardStatement scope(failure) doSomethingOnException(); //code that might throw The block inside the scope statement will run when the surrounding scope is exited with an exception. That _really_ cleans up a lot of code that just wants to react to the fact that an exception was thrown and not actually do anything with it. - Jonathan M Davis
Yes, scope(...) does seem useful in certain situations. In my case I need access to the information contained in the Exception object so that I can log what kind of error occurred and also whatever other details there are, and then perform a few general operations such as possibly sending out a notification to support staff. I am thinking that perhaps a callback may do what I want, so that's something I intend to look at more closely. --rt
Mar 08 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 20:16:13 Rob T wrote:
 On Friday, 8 March 2013 at 18:49:53 UTC, Jonathan M Davis wrote:
 Except that the C++ one is just as pointless. In both cases,
 you're telling it
 to catch everything. It's just that syntax is slightly
 different, because D
 doesn't allow you to throw without an explicit variable. And
 it's only a
 handful of characters difference in length. So, to some of us
 at least, it
 seems like you're blowing things out of proportion. And given
 the lack of
 clarity in the C++ solution, it comes off as being worse from a
 technical
 perspective, regardless of the typing involved.
 
 - Jonathan M Davis
I don't wish to blow things out of proportion, and will say again that the main objective I was trying to achieve has been met, thanks to the assistance I received in here, so this remaining item is not all that major, it's just an unnecessary repetitive nuisance to me. From a technical stand point, I'm implementing a reusable exception handler or dispatcher (I've seen these two terms used to describe it) which is extremely useful to me, and I would assume to many others. There are examples of this concept implemented in C++ by other programmers, that's how I got the idea. Before I started using an exception handler, my exception handling was very limited and tedious to implement, and I never saw a need to re-throw an exception. There may be other uses for rethrow that I'm not aware of. What my C++ exception handler does not require, is the exception reference passed in as an argument, so that's one of the main differences between what D allows and what C++ allows. In my case every catch statement and function call will be identical, it's slightly more tedious to type in than the C++ version. No big deal for you, but it is annoying for me because I use this form very frequently. If you know of a better way to implement an exception handler in D, then I'd like to know about it. For example I do know that D's system allows you to insert callback functions, but I don't yet know how to make use out of it, so perhaps there's a better way. Any further help or insight on this matter is appreciated.
Well, ultimately, it looks like the only difference between C++ and D on this, would be that std::exception Trace() { try { // key item missing from D throw; // <= rethrow last exception } catch( EType1 &E ) { // do stuff return new std::exception( ... } catch( EType2 &E ) { // do different stuff return new std::exception( ... } catch(...) { // unkown type, do something else throw new std::exception( ... } } would become Exception Trace(Exception e) { try { // key item missing from D throw e; // <= rethrow last exception } catch( EType1 &e ) { // do stuff return new std::exception( ... } catch( EType2 &e ) { // do different stuff return new std::exception( ... } catch(...) { // unkown type, do something else throw new std::exception( ... } } or this Exception Trace(Exception e) { if(cast(Etype1)e) { // do stuff return new Exception( ... } else if(cast(Etype2)e) { // do different stuff return new Exception( ... } else { // unkown type, do something else throw new Exception( ... } } And in the caller, try {...} catch(...) { throw Trace(); } would become try {...} catch(Exception e) { throw Trace(e); } So, ultimately, the code is nearly identical, and if you use casts, you can actually make Trace shorter and more efficient (since it avoids the extra throw). And so while D may not improve on the C++ code much, it seems to me that you can do pretty much exactly the same thing in both. There are differences, but they're quite minimal. - Jonathan M Davis
Mar 08 2013
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/8/13, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 In both cases, you're telling it to catch everything.
Also, catch points should be rare, especially the ones which catch base types like Exception or even Error or Throwable. The problem is not the syntax, but the way people use exceptions. Pokemon exception handling is a bad idiom.
Mar 08 2013
parent "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 18:56:38 UTC, Andrej Mitrovic wrote:
 On 3/8/13, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 In both cases, you're telling it to catch everything.
Also, catch points should be rare, especially the ones which catch base types like Exception or even Error or Throwable. The problem is not the syntax, but the way people use exceptions. Pokemon exception handling is a bad idiom.
I've given this a fair amount of thought in the past, and I've have extensive experience with making good use out of error handling for managing large code bases that require near real time automated monitoring for defects and rapid repair. My needs may be much more unique than most. What I will say, is that unless you use an exception handler, and have a well designed exception handling system in place, you will have plenty of problems making use out of frequent try/catch blocks. They may in fact cause more problems than they solve. In a small non essential code base, it may seem pointless as well. So beware that what is good or bad depends entirely on the implementation and the needs. --rt
Mar 08 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/08/2013 12:39 AM, Rob T wrote:
 In C++ you can do this

 std::exception Trace()
 {
 try
 {
 // key item missing from D
 throw; // <= rethrow last exception
This idiom is know as a Lippincott Function. Ali
Mar 08 2013
parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 17:40:38 UTC, Ali Çehreli wrote:
 On 03/08/2013 12:39 AM, Rob T wrote:
 In C++ you can do this

 std::exception Trace()
 {
 try
 {
 // key item missing from D
 throw; // <= rethrow last exception
This idiom is know as a Lippincott Function. Ali
I'm having trouble finding references on Lippincott Function, so if you have any more information, please let me know. Thanks. --rt
Mar 08 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/08/2013 11:26 AM, Rob T wrote:
 On Friday, 8 March 2013 at 17:40:38 UTC, Ali Çehreli wrote:
 On 03/08/2013 12:39 AM, Rob T wrote:
 In C++ you can do this

 std::exception Trace()
 {
 try
 {
 // key item missing from D
 throw; // <= rethrow last exception
This idiom is know as a Lippincott Function. Ali
I'm having trouble finding references on Lippincott Function, so if you have any more information, please let me know. Thanks. --rt
I heard about this idiom for the first time in Jon Kalb's talk. The name appears in his slides: http://exceptionsafecode.com/ Very smart way of writing a single function that catches many different types of exceptions; does special things about them, like producing special error codes, and then returns those codes to the C world. I am familiar with your use case: When a C layer calls C++, the exceptions must be caught and converted to error codes. This is how we do it: #define BEGIN_C_INTERFACE try { #define END_C_INTERFACE \ } catch (const SomeType & e) { \ // ... special code for SomeType \ } catch (const SomeOtherType & e) { \ // ... special code for SomeOtherType \ \ // ... etc. \ \ } catch( ... ) { \ log("Unhandled exception"); \ return some_generic_error_code; \ } Then our C++ functions that are called from C are like this: extern "C" int my_api_func() { BEGIN_C_INTERFACE // ... the actual body of the function END_C_INTERFACE } Lippincott functions avoid macros and make it more explicit that the entire body is inside a try block. Ali
Mar 08 2013
parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 22:10:19 UTC, Ali Çehreli wrote:
 I heard about this idiom for the first time in Jon Kalb's talk. 
 The name appears in his slides:

   http://exceptionsafecode.com/

 Very smart way of writing a single function that catches many 
 different types of exceptions; does special things about them, 
 like producing special error codes, and then returns those 
 codes to the C world.
Thanks for the link and info!
 I am familiar with your use case: When a C layer calls C++, the 
 exceptions must be caught and converted to error codes. This is 
 how we do it:

 #define BEGIN_C_INTERFACE try {

 #define END_C_INTERFACE                                     \
 } catch (const SomeType & e) {                              \
   // ... special code for SomeType                          \
 } catch (const SomeOtherType & e) {                         \
   // ... special code for SomeOtherType                     \
                                                             \
 // ... etc.                                                 \
                                                             \
 } catch( ... ) {                                            \
     log("Unhandled exception");                             \
     return some_generic_error_code;                         \
 }

 Then our C++ functions that are called from C are like this:

 extern "C"
 int my_api_func()
 {
     BEGIN_C_INTERFACE

     // ... the actual body of the function

     END_C_INTERFACE
 }

 Lippincott functions avoid macros and make it more explicit 
 that the entire body is inside a try block.

 Ali
You seem to understand the use case, but why is your example not making use of it? I was expecting something like this ... int errFromException() { try { throw; } catch (const SomeType & e) { // ... special code for SomeType return errSomeType; } catch (const SomeOtherType & e) { // ... special code for SomeOtherType return errSomeOtherType; } catch ( ... { ... etc catch( ... ) { log("Unhandled exception"); return some_generic_error_code; } } extern "C" int my_api_func() { try { // body of my_api_func return noerror; } catch(...) { return errFromException(); } } No more ugly macros and you have the ability to custom fit the try catch block to perform any unique things that the function may require when an exception is thrown. --rt
Mar 10 2013
parent reply "Rob T" <alanb ucora.com> writes:
 Lippincott functions avoid macros and make it more explicit 
 that the entire body is inside a try block.

 Ali
Oops, I think you were showing me an example where it could be used. --rt
Mar 10 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/10/2013 08:10 PM, Rob T wrote:
 Lippincott functions avoid macros and make it more explicit that the
 entire body is inside a try block.

 Ali
Oops, I think you were showing me an example where it could be used.
Yes but we still use the macros! The macros were written ten years ago but I learned about this idiom two months ago. :) Ali
Mar 10 2013
parent "Rob T" <alanb ucora.com> writes:
On Monday, 11 March 2013 at 03:46:22 UTC, Ali Çehreli wrote:
 On 03/10/2013 08:10 PM, Rob T wrote:
 Lippincott functions avoid macros and make it more explicit
that the
 entire body is inside a try block.

 Ali
Oops, I think you were showing me an example where it could
be used. Yes but we still use the macros! The macros were written ten years ago but I learned about this idiom two months ago. :) Ali
Ouch, 10 years too late, but I bet you are looking forward to using it in your new code. I was stuck with macros similar to that for a few years. It was unbearable because at times I had custom operations to perform within a catch, but the macros had various levels of standard error logging and reporting, so deciphering the macros and inserting new operations was not fun and defeated the purpose making it very difficult to maintain. Even more macros appeared to try and deal with it. When we started building a new library, I searched in desperation for a better solution and luckily stumbled on the one that used the rethrow, what a relief! Unfortunately the old code still needs to be maintained for several more years. Unlike in C++ we only have to worry about catching Throwable and objects derived from it, so things are much better off simply because of that. I always thought it to be silly to allow anything to be thrown because you'd never be able to know what to catch unless you had complete trust in the code. When I first looked at D it was improvements like this that had me very eager to try it out. Anyway, thanks for your input, much appreciated! PS: Your D Programming Tutorial is excellent, many thanks! You may want to add a note about the Lippincott idiom in there. --rt
Mar 10 2013
prev sibling parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 06:05:02 UTC, Maxim Fomin wrote:
     catch (Exception e) {
         if (typeid(e) == typeid(myException1))
             throw e; // may be downcasted, if necessary
                      // to work with specific fields
     }
Isn't it better to check identity in this way? if (typeid(e) is typeid(myException1)) --rt
Mar 08 2013
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Mar 08, 2013 at 08:52:21PM +0100, Rob T wrote:
 On Friday, 8 March 2013 at 06:05:02 UTC, Maxim Fomin wrote:
    catch (Exception e) {
        if (typeid(e) == typeid(myException1))
            throw e; // may be downcasted, if necessary
                     // to work with specific fields
    }
Isn't it better to check identity in this way? if (typeid(e) is typeid(myException1))
[...] Couldn't you just do this? auto myExc = cast(myException1)e; if (myExc !is null) { // do stuff with myExc } ? Or am I missing the point here? T -- Дерево держится корнями, а человек - друзьями.
Mar 08 2013
parent "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 19:58:10 UTC, H. S. Teoh wrote:
 On Fri, Mar 08, 2013 at 08:52:21PM +0100, Rob T wrote:
 On Friday, 8 March 2013 at 06:05:02 UTC, Maxim Fomin wrote:
    catch (Exception e) {
        if (typeid(e) == typeid(myException1))
            throw e; // may be downcasted, if necessary
                     // to work with specific fields
    }
Isn't it better to check identity in this way? if (typeid(e) is typeid(myException1))
[...] Couldn't you just do this? auto myExc = cast(myException1)e; if (myExc !is null) { // do stuff with myExc } ? Or am I missing the point here? T
I didn't know that casting a base class to a derived class that the base does not refer to will resolve to a null. Nice to know. I suppose that's another way to do the same thing which may be more convenient depending the situation. Thanks for suggesting it. --rt
Mar 08 2013
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 11:56:12 H. S. Teoh wrote:
 On Fri, Mar 08, 2013 at 08:52:21PM +0100, Rob T wrote:
 On Friday, 8 March 2013 at 06:05:02 UTC, Maxim Fomin wrote:
 catch (Exception e) {
 
 if (typeid(e) == typeid(myException1))
 
 throw e; // may be downcasted, if necessary
 
 // to work with specific fields
 
 }
Isn't it better to check identity in this way? if (typeid(e) is typeid(myException1))
[...] Couldn't you just do this? auto myExc = cast(myException1)e; if (myExc !is null) { // do stuff with myExc } ? Or am I missing the point here?
That's the way that it's supposed to be done. I don't know why anyone would mess around with typeid that. - Jonathan M Davis
Mar 08 2013
parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 20:46:42 UTC, Jonathan M Davis wrote:
 On Friday, March 08, 2013 11:56:12 H. S. Teoh wrote:
 On Fri, Mar 08, 2013 at 08:52:21PM +0100, Rob T wrote:
 On Friday, 8 March 2013 at 06:05:02 UTC, Maxim Fomin wrote:
 catch (Exception e) {
 
 if (typeid(e) == typeid(myException1))
 
 throw e; // may be downcasted, if necessary
 
 // to work with specific fields
 
 }
Isn't it better to check identity in this way? if (typeid(e) is typeid(myException1))
[...] Couldn't you just do this? auto myExc = cast(myException1)e; if (myExc !is null) { // do stuff with myExc } ? Or am I missing the point here?
That's the way that it's supposed to be done. I don't know why anyone would mess around with typeid that. - Jonathan M Davis
So this is more efficient or has some other advantages than using typeid? if ( cast(myException1)e !is null ) { // do stuff with myException1 } else if ( cast(myException2)e !is null ) { // do stuff with myException2 } else if ( cast ... --rt
Mar 08 2013
next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/8/13, Rob T <alanb ucora.com> wrote:
 So this is more efficient or has some other advantages than using
 typeid?
Benchmark! :) Also you might find this useful some day: http://wiki.dlang.org/Dispatching_an_object_based_on_its_dynamic_type
Mar 08 2013
parent "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 21:10:15 UTC, Andrej Mitrovic wrote:
 On 3/8/13, Rob T <alanb ucora.com> wrote:
 So this is more efficient or has some other advantages than 
 using
 typeid?
Benchmark! :) Also you might find this useful some day: http://wiki.dlang.org/Dispatching_an_object_based_on_its_dynamic_type
Very interesting. Thanks! --rt
Mar 10 2013
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Friday, 8 March 2013 at 21:04:06 UTC, Rob T wrote:
 On Friday, 8 March 2013 at 20:46:42 UTC, Jonathan M Davis wrote:
 On Friday, March 08, 2013 11:56:12 H. S. Teoh wrote:
 On Fri, Mar 08, 2013 at 08:52:21PM +0100, Rob T wrote:
 On Friday, 8 March 2013 at 06:05:02 UTC, Maxim Fomin wrote:
 catch (Exception e) {
 
 if (typeid(e) == typeid(myException1))
 
 throw e; // may be downcasted, if necessary
 
 // to work with specific fields
 
 }
Isn't it better to check identity in this way? if (typeid(e) is typeid(myException1))
[...] Couldn't you just do this? auto myExc = cast(myException1)e; if (myExc !is null) { // do stuff with myExc } ? Or am I missing the point here?
That's the way that it's supposed to be done. I don't know why anyone would mess around with typeid that. - Jonathan M Davis
So this is more efficient or has some other advantages than using typeid? if ( cast(myException1)e !is null ) { // do stuff with myException1 } else if ( cast(myException2)e !is null ) { // do stuff with myException2 } else if ( cast ... --rt
Please read comments as well as code - they were important. typeid(e) == typeid(myException) is useful for simple query (identity operator is better) and costs here is call to opEquals (with identity operator there is simple comparison) Casting leads to call to _d_isbaseof2() rt function which is slower than the first, but it can be a necessity.
Mar 08 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 22:04:03 Rob T wrote:
 So this is more efficient or has some other advantages than using
 typeid?
 
 if ( cast(myException1)e !is null )
 {
 // do stuff with myException1
 }
 else
 if ( cast(myException2)e !is null )
 {
 // do stuff with myException2
 }
 else
 if ( cast ...
I'd have to benchmark it to be 100% sure, but I'd be very surprised if using typeid were faster. It involves getting the typeid (which may mean making a function call), and I believe that typeid gives you a struct, which then gets compared with opEquals. Contrast this with the cast which should be able to just look at the vtbl and then set then do the cast if it can or result in null if it can't. Regardless, as I understand it, casting is the "official" way to check whether a object is an instance of a particular type. Also, you can actually make the ifs even shorter if you want to if(cast(MyException1)e) {...} else if(cast(MyException2)e) {...} as using a class reference directly in a condition will check whether it's null. - Jonathan M Davis
Mar 08 2013
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 06:46:47 Rob T wrote:
 That's very unfortunate, and should be corrected, because it
 means that you cannot easily catch multiple derived Exception
 types and rethrow the same derived type. Instead you have to
 explicitly catch all derived types and rethrow them individually,
 but that's simply not practical, so you end up catching only the
 base exception (Throwable?) and rethrow it, but you lose the
 derived type in the process.
No you don't. It doesn't matter what the type you catch with, since Exceptions are classes, they retain their original type when they're caught using a base class, and when they're rethrown. And the only reason that you'd lose the derived type in C++ doing exactly the same thing that you'd do in D would be because you were ignorant enough to catch by value rather than reference (which arguably shouldn't even be legal given the various hazards in doing so). C++ has no exception capabilities that D doesn't have. If you truly want to catch _everything_ and then rethrow it, then just do try {...} catch(Throwable t) { ... throw t; } But you should never catch Throwable or Error unless you know what you're doing. Exceptions that are meant to be caught are derived from Exception. So, it would be _far_ better to do try {...} catch(Exception e) { ... throw e; } But if all you're going to do is rethrow it, and you don't care about the exception's type, then you should just use a scope statement: scope(failure) ... - Jonathan M Davis
Mar 07 2013
parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 06:09:48 UTC, Jonathan M Davis wrote:
[...]
 C++ has no exception capabilities that D doesn't have.
Except that D cannot rethrow without explicitly catching. That may seem like a very minor item, but as I explained in my last post, the extra boiler plate coding can add up on larger sized projects. Anyway, I got enough of my problem solved to move on, so I'm back to being very happy with D. Thanks for the help! --rt
Mar 07 2013
parent reply "Rob T" <alanb ucora.com> writes:
One more thing, we finally got __FUNCTION__ (and more) added to 
MASTER so that's another missing item that was sorely missed. Now 
we can easily log what functions are catching and throwing 
exceptions, and more.

The big question is if Throwable will be expanded to 
automatically capture the function signature (as it does with 
line and file)? I hope there are no major concerns over legacy 
code breakage and it gets added in.

--rt
Mar 07 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-03-08 08:34, Rob T wrote:
 One more thing, we finally got __FUNCTION__ (and more) added to MASTER
 so that's another missing item that was sorely missed. Now we can easily
 log what functions are catching and throwing exceptions, and more.

 The big question is if Throwable will be expanded to automatically
 capture the function signature (as it does with line and file)? I hope
 there are no major concerns over legacy code breakage and it gets added in.
I'm pretty sure there is no concerns. We could just add another overload of the constructor or add an additional default parameter. If a default parameter is added it needs to be added last, which would result some somewhat inconsistent order for the parameters. So I vote for a new overload. -- /Jacob Carlborg
Mar 08 2013
parent "Rob T" <alanb ucora.com> writes:
On Friday, 8 March 2013 at 09:01:29 UTC, Jacob Carlborg wrote:
 On 2013-03-08 08:34, Rob T wrote:
 One more thing, we finally got __FUNCTION__ (and more) added 
 to MASTER
 so that's another missing item that was sorely missed. Now we 
 can easily
 log what functions are catching and throwing exceptions, and 
 more.

 The big question is if Throwable will be expanded to 
 automatically
 capture the function signature (as it does with line and 
 file)? I hope
 there are no major concerns over legacy code breakage and it 
 gets added in.
I'm pretty sure there is no concerns. We could just add another overload of the constructor or add an additional default parameter. If a default parameter is added it needs to be added last, which would result some somewhat inconsistent order for the parameters. So I vote for a new overload.
Yes that is my choice as well, just add another overload to Throwable and Exception. Exception has the default argument set to __PRETTY_FUNCTION__ which is normally what you'd want to see. --rt
Mar 08 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 19:56:28 Andrej Mitrovic wrote:
 Pokemon exception handling
LOL. I'll have to remember that term! - Jonathan M Davis
Mar 08 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, March 08, 2013 15:46:30 Jonathan M Davis wrote:
 That's the way that it's supposed to be done. I don't know why anyone would
 mess around with typeid that.
"with typeid _like_ that." My fingers don't seem to keep up with my brain very well... - Jonathan M Davis
Mar 08 2013