digitalmars.D.learn - Exception handling - the basics
- Mathias (32/32) Oct 20 2005 Hello,
- Regan Heath (76/76) Oct 20 2005 Here are a few examples, ask any questions you want.
- Mathias (17/93) Oct 21 2005 Thanks for the examples. For now, I'm only looking into the first (simpl...
- Deewiant (28/44) Oct 21 2005 Yes, it creates a new Exception object, which is then thrown.
- Mathias (11/55) Oct 21 2005 Yes that makes it clearer for me. However, still a question:
- Sean Kelly (16/21) Oct 21 2005 No. The only exception object that is created is when you call 'new'. ...
- Mathias (16/16) Oct 22 2005 Ah, I think I'm beginning to understand... ;-) I was confused by the lin...
- Sean Kelly (17/24) Oct 22 2005 Right. It's a bit like an inline function call. You can also have a se...
- Sean Kelly (30/36) Oct 22 2005 By the way, the compiler is not forced to process an exception in any sp...
- John C (12/63) Oct 23 2005 Just to correct you, D does have an equivalent to C++'s catch (...), and...
- Mathias (6/6) Oct 23 2005 Thanks heaps for your answers, Sean and John. I'm not sure I understand
-
=?utf-8?B?RGF3aWQgQ2nEmcW8YXJraWV3aWN6?=
(38/58)
Oct 23 2005
Yes, but no.
I see that you "hear the bell but don't know in which - Mathias (12/21) Oct 24 2005 Coming from C, I once tried to learn C++, which I found rather confusing...
Hello, I come from a C background (no C++), and I haven't got any idea how D's exception handling works. The D reference document doesn't provide examples, and the tutorial on dsource only covers one side - how to catch exceptions - but not how to throw them. If there is a tutorial that I can use for this, I'd be glad to hear about it. Please consider the program below that uses C style error handling. How could I rewrite it to use D style exceptions? Thanks, Mathias import std.c.stdio; int foo(int bar) /* Let's assume that for some reason 10 < bar < 20 is necessary */ { if(bar<10) return -1; else if(bar>20) return 1; else return 0; } void main() { int result; result = foo(15); if(result == -1) printf("bar too small!\n"); else if(result == 1) printf("bar too large!\n"); else if(result == 0) printf("bar O.K.!\n"); }
Oct 20 2005
Here are a few examples, ask any questions you want. import std.stdio; /* SIMPLE EXAMPLE */ /**/ void foo(int bar) { if (bar<10) throw new Exception("bar too small!"); if (bar>20) throw new Exception("bar too large!"); } void main() { try { foo(15); } catch(Exception e) { writefln(e); } } /**/ /* CUSTOM EXCEPTION EXAMPLE */ /** class TooSmallException : Exception { this() { super("bar too small!"); } } class TooLargeException : Exception { this() { super("bar too large!"); } } void foo(int bar) { if (bar<10) throw new TooSmallException(); if (bar>20) throw new TooLargeException(); } void main() { try { foo(15); } catch(TooSmallException e) { writefln("SMALL,",e); } catch(TooLargeException e) { writefln("LARGE,",e); } } /**/ /* ASSERT/CONTRACT EXAMPLE */ /** void foo(int bar) in { assert(bar>10 && bar<20); } body { } void main() { foo(15); } /**/ /* ORIGINAL */ /** int foo(int bar) //Let's assume that for some reason 10 < bar < 20 is necessary { if(bar<10) return -1; else if(bar>20) return 1; else return 0; } void main() { int result; result = foo(15); if(result == -1) printf("bar too small!\n"); else if(result == 1) printf("bar too large!\n"); else if(result == 0) printf("bar O.K.!\n"); } /**/ Regan
Oct 20 2005
Thanks for the examples. For now, I'm only looking into the first (simple) example: Does this line from your example create a new Exception object? If no, what is it that is actually "thrown"? Or is a class object created below in the main program? That means, in this line: It seems a bit weird to me that a class object is thrown before it's created. Finally, why is writefln necessary to print the line? I was under the - probably false - impression that printf and writef do essentially the same. However, trying to print the line using: yields an Error: Access Violation. Not that I insist on using printf, I'm just curious. Thanks for your patience :-) Mathias In article <opsyyozkzg23k2f5 nrage.netwin.co.nz>, Regan Heath says...Here are a few examples, ask any questions you want. import std.stdio; /* SIMPLE EXAMPLE */ /**/ void foo(int bar) { if (bar<10) throw new Exception("bar too small!"); if (bar>20) throw new Exception("bar too large!"); } void main() { try { foo(15); } catch(Exception e) { writefln(e); } } /**/ /* CUSTOM EXCEPTION EXAMPLE */ /** class TooSmallException : Exception { this() { super("bar too small!"); } } class TooLargeException : Exception { this() { super("bar too large!"); } } void foo(int bar) { if (bar<10) throw new TooSmallException(); if (bar>20) throw new TooLargeException(); } void main() { try { foo(15); } catch(TooSmallException e) { writefln("SMALL,",e); } catch(TooLargeException e) { writefln("LARGE,",e); } } /**/ /* ASSERT/CONTRACT EXAMPLE */ /** void foo(int bar) in { assert(bar>10 && bar<20); } body { } void main() { foo(15); } /**/ /* ORIGINAL */ /** int foo(int bar) //Let's assume that for some reason 10 < bar < 20 is necessary { if(bar<10) return -1; else if(bar>20) return 1; else return 0; } void main() { int result; result = foo(15); if(result == -1) printf("bar too small!\n"); else if(result == 1) printf("bar too large!\n"); else if(result == 0) printf("bar O.K.!\n"); } /**/ Regan
Oct 21 2005
Mathias wrote:Thanks for the examples. For now, I'm only looking into the first (simple) example: Does this line from your example create a new Exception object? If no, what is it that is actually "thrown"? Or is a class object created below in the main program?Yes, it creates a new Exception object, which is then thrown. The rule of thumb is that if you're not sure what something does, read it out as an English sentence - "throw new exception": a new exception is thrown ;-) (Okay, it doesn't always work that well, but it's worth a try.)Finally, why is writefln necessary to print the line? I was under the - probably false - impression that printf and writef do essentially the same. However, trying to print the line using: yields an Error: Access Violation. Not that I insist on using printf, I'm just curious.printf and writef differ in a couple of ways. One of these is that writef implicitly calls the toString method of any object it is passed: writef(e) is the same as writef(e.toString()) is the same as writef("%s", e.toString()) is the same as printf("%.*s", e.toString()). A small example to illustrate this: import std.stdio; class X { char[] toString() { return "abc"; } } int main() { X x = new X; writefln(x); // "abc" writefln(x.toString); // "abc" writefln("%s", x); // "abc" writefln("%s", x.toString); // "abc" printf("%.*s\n", x.toString()); // "abc" printf("%.*s\n", x); // "%.*s" return 0; } That didn't go quite as I hoped, the last printf doesn't give an access violation error, and I'm not quite sure why :-) I hope I managed to explain the problem in your case, though.
Oct 21 2005
Yes that makes it clearer for me. However, still a question: Does this create an Exception object as well? Does that mean that the program creates two Exception objects, one where the exception is thrown, and the other where it is catched? Also, would you agree that the docs are not complete with regards to writef et al? Or are the things you explained to me there, just that I didn't find them? If so, where are they? Thank you for your time, Mathias In article <djbdmf$2gqk$1 digitaldaemon.com>, Deewiant says...Mathias wrote:Thanks for the examples. For now, I'm only looking into the first (simple) example: Does this line from your example create a new Exception object? If no, what is it that is actually "thrown"? Or is a class object created below in the main program?Yes, it creates a new Exception object, which is then thrown. The rule of thumb is that if you're not sure what something does, read it out as an English sentence - "throw new exception": a new exception is thrown ;-) (Okay, it doesn't always work that well, but it's worth a try.)Finally, why is writefln necessary to print the line? I was under the - probably false - impression that printf and writef do essentially the same. However, trying to print the line using: yields an Error: Access Violation. Not that I insist on using printf, I'm just curious.printf and writef differ in a couple of ways. One of these is that writef implicitly calls the toString method of any object it is passed: writef(e) is the same as writef(e.toString()) is the same as writef("%s", e.toString()) is the same as printf("%.*s", e.toString()). A small example to illustrate this: import std.stdio; class X { char[] toString() { return "abc"; } } int main() { X x = new X; writefln(x); // "abc" writefln(x.toString); // "abc" writefln("%s", x); // "abc" writefln("%s", x.toString); // "abc" printf("%.*s\n", x.toString()); // "abc" printf("%.*s\n", x); // "%.*s" return 0; } That didn't go quite as I hoped, the last printf doesn't give an access violation error, and I'm not quite sure why :-) I hope I managed to explain the problem in your case, though.
Oct 21 2005
In article <djbgmb$2jqb$1 digitaldaemon.com>, Mathias says...Yes that makes it clearer for me. However, still a question: Does this create an Exception object as well? Does that mean that the program creates two Exception objects, one where the exception is thrown, and the other where it is catched?No. The only exception object that is created is when you call 'new'. From there, the pointer/handle is passed to the catch clause. You can even do something like this if you really want to: static Exception myExcept; static this { myExcept = new Exception; } void main() { try { throw myExcept; } catch( Exception e ) { printf( "%.*s\n", e.toString() ); } } ie. it's not strictly necessary to dynamically allocate an exception object as a part of the throw process. Sean
Oct 21 2005
Ah, I think I'm beginning to understand... ;-) I was confused by the line: and what it does. I didn't understand why I couldn't simply write: I think the correct answer is that the compiler simply doesn't know what "e" is since it is created in another function. The fact that the throwing function knows what kind of object it throws doesn't change this. "catch(e)" just tells the compiler "catch something called 'e'", and the compiler replies: "I can't do anything unless I know what kind of data 'e' is." "catch (Exception e)" tells the compiler "catch an Exception object that we call 'e' here" and the compiler says "O.K." If both throw and catch were located within the same function, I could indeed simply write catch(e). I hope this is correct now. (If not, please tell me so.) Thanks, Mathias
Oct 22 2005
In article <djd3ab$138g$1 digitaldaemon.com>, Mathias says...Ah, I think I'm beginning to understand... ;-) I was confused by the line: and what it does. I didn't understand why I couldn't simply write: I think the correct answer is that the compiler simply doesn't know what "e" is since it is created in another function. The fact that the throwing function knows what kind of object it throws doesn't change this.Right. It's a bit like an inline function call. You can also have a series of catch exceptions, and the one that is called will be the first one that matches: class MyException : Exception {} try { throw new MyException; } catch( MyException e ) {} // exact match, so enter this catch clause catch( Exception e ) {} try { throw new MyException; } catch( Exception e ) {} // MyException implicitly converts to Exception because it derives from this class--enter this catch clause catch( MyException e ) {} // even though this is a better match, it will not be called before catch(Exception) will be evaluated first Sean
Oct 22 2005
In article <djd3ab$138g$1 digitaldaemon.com>, Mathias says..."catch(e)" just tells the compiler "catch something called 'e'", and the compiler replies: "I can't do anything unless I know what kind of data 'e' is." "catch (Exception e)" tells the compiler "catch an Exception object that we call 'e' here" and the compiler says "O.K."By the way, the compiler is not forced to process an exception in any specific scope--it will just keep unwinding the stack until it finds an appropriate catch handler. For example: class MyException {} // note, not derived from Exception void f1() { throw new MyException; } void f2() { try { f1(); } catch( Exception e ) {} // will be skipped because MyException does not derive from Exception } void f3() { try { f2(); } catch( Exception e ) {} // will be skipped as well catch( MyException e ) {} // exact match, process exception here catch( Object o ) {} // since all classes are objects, this is equivalent to "catch anything" } That said, I believe that all exceptions that are defined should inherit from Exception, and that you should only ever throw these objects. While the language may not prevent you from throwing other things (arrays, integers, etc), it's bad form to do so (I'm actually not sure if D lets you throw integers and such or not, but I thought I'd mention it just in case).If both throw and catch were located within the same function, I could indeed simply write catch(e).Not in D. As I said in my other post, catch clauses are kind of like inline functions--you must declare the type of exception they are meant to handle and a name for this variable. C++ allows "catch(...)" for "catch anything," but D has no direct equivalent--the closest you can get is "catch(Object o)." Sean
Oct 22 2005
"Sean Kelly" <sean f4.ca> wrote in message news:djer01$r2t$1 digitaldaemon.com...In article <djd3ab$138g$1 digitaldaemon.com>, Mathias says...Just to correct you, D does have an equivalent to C++'s catch (...), and it's 'catch' on it's own. try { throw new Exception("Exception thrown."); } catch { // catches anything - eg, when you're not interested in what was thrown } John."catch(e)" just tells the compiler "catch something called 'e'", and the compiler replies: "I can't do anything unless I know what kind of data 'e' is." "catch (Exception e)" tells the compiler "catch an Exception object that we call 'e' here" and the compiler says "O.K."By the way, the compiler is not forced to process an exception in any specific scope--it will just keep unwinding the stack until it finds an appropriate catch handler. For example: class MyException {} // note, not derived from Exception void f1() { throw new MyException; } void f2() { try { f1(); } catch( Exception e ) {} // will be skipped because MyException does not derive from Exception } void f3() { try { f2(); } catch( Exception e ) {} // will be skipped as well catch( MyException e ) {} // exact match, process exception here catch( Object o ) {} // since all classes are objects, this is equivalent to "catch anything" } That said, I believe that all exceptions that are defined should inherit from Exception, and that you should only ever throw these objects. While the language may not prevent you from throwing other things (arrays, integers, etc), it's bad form to do so (I'm actually not sure if D lets you throw integers and such or not, but I thought I'd mention it just in case).If both throw and catch were located within the same function, I could indeed simply write catch(e).Not in D. As I said in my other post, catch clauses are kind of like inline functions--you must declare the type of exception they are meant to handle and a name for this variable. C++ allows "catch(...)" for "catch anything," but D has no direct equivalent--the closest you can get is "catch(Object o)."Sean
Oct 23 2005
Thanks heaps for your answers, Sean and John. I'm not sure I understand everything that you say, but my main questions are answered. I guess I will re-read your posts, test it on my computer, and someday I'll get the remainder. ;-) Thanks again, Mathias
Oct 23 2005
On Sat, 22 Oct 2005 12:12:27 +0200, Mathias <Mathias_member pathlink.com> wrote:Ah, I think I'm beginning to understand... ;-) I was confused by the line: and what it does. I didn't understand why I couldn't simply write: I think the correct answer is that the compiler simply doesn't know what "e" is since it is created in another function. The fact that the throwing function knows what kind of object it throws doesn't change this. "catch(e)" just tells the compiler "catch something called 'e'", and the compiler replies: "I can't do anything unless I know what kind of data 'e' is." "catch (Exception e)" tells the compiler "catch an Exception object that we call 'e' here" and the compiler says "O.K." If both throw and catch were located within the same function, I could indeed simply write catch(e). I hope this is correct now. (If not, please tell me so.)Yes, but no. <g> I see that you "hear the bell but don't know in which church does it ring". :) 1. Languages with "strong typing" (i'm not sure is this right term) have to know of which type is every used variable before they'll use it. They just have to reserve fixed amount of bytes first. And they have to know what you can do with such variable, and what you can not. This is one and you seem to get it. 2. But there is another reason too: You can have many "catch" clauses, and you have to tell the compiler which type of throwed object you want to handle. That it why even in PHP (where variables may be one time strings and another something else) you have to specify what do you want to handle. In folowing example you can do "something completly diffrent" if assercion failed and "something completly diffrent" if other type of exception was throwed. try { ... } catch (AssertException a) { writef("Assert"); } catch (Exception e) { writef("other exception"); } That is why even if throw and catch would be in same function you have to add type first. They could be just many throws in such function and each of them could throw diffrent things. I do not wish you to turn you off using this group (as you can see many helpful people are here), but I think you should propably find some good book/web resource to learn faster about standard programing concepts like exceptions. D is very similar to C++ in many concepts so don't be afraid to use C++ examples (there is much more of them in the moment). What you have to keep in mind (dealing with exceptions in D, knowing how they work in C++) is that Objects in D are allways passed by reference (no copying is ever made, only handlers are passed) and of course D has neat "finally" keyword. Regards, -- Dawid Ciężarkiewicz
Oct 23 2005
In article <op.sy4c2qee58xlqs localhost.localdomain>, =?utf-8?B?RGF3aWQgQ2nEmcW8YXJraWV3aWN6?= says...I do not wish you to turn you off using this group (as you can see many helpful people are here), but I think you should propably find some good book/web resource to learn faster about standard programing concepts like exceptions. D is very similar to C++ in many concepts so don't be afraid to use C++ examples (there is much more of them in the moment). What you have to keep in mind (dealing with exceptions in D, knowing how they work in C++) is that Objects in D are allways passed by reference (no copying is ever made, only handlers are passed) and of course D has neat "finally" keyword.Coming from C, I once tried to learn C++, which I found rather confusing. D seemed like an easier alternative, but in a sense it requires C++ knowledge anyway. A standalone, no prior knowledge requiring D tutorial would be useful. (More detailed, comprehensive and up-to-date than the one on dource.org.) It doesn't seem that there is something in hand, however. Anyway, thanks for your hints, they made things clearer for me. I'll also look into some C++ books. You are probably right in that this is a faster way to finally "get" it. Thanks again, Mathias
Oct 24 2005