Jump to page: 1 2
Thread overview
Exception handling - the basics
Oct 20, 2005
Mathias
Oct 20, 2005
Regan Heath
Oct 21, 2005
Mathias
Oct 21, 2005
Deewiant
Oct 21, 2005
Mathias
Oct 21, 2005
Sean Kelly
Oct 22, 2005
Mathias
Oct 22, 2005
Sean Kelly
Oct 23, 2005
Sean Kelly
Oct 23, 2005
John C
Oct 23, 2005
Mathias
Oct 24, 2005
Mathias
October 20, 2005
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");
}


October 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
October 21, 2005
Thanks for the examples. For now, I'm only looking into the first (simple)
example:

# if (bar<10) throw new Exception("bar too small!");

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:

# catch(Exception e)

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:

# printf("%.*s\n", e);

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


October 21, 2005
Mathias wrote:
> Thanks for the examples. For now, I'm only looking into the first (simple)
> example:
> 
> # if (bar<10) throw new Exception("bar too small!");
> 
> 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:
> 
> # printf("%.*s\n", e);
> 
> 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.
October 21, 2005
Yes that makes it clearer for me. However, still a question:

# catch(Exception e)

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:
>> 
>> # if (bar<10) throw new Exception("bar too small!");
>> 
>> 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:
>> 
>> # printf("%.*s\n", e);
>> 
>> 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.


October 21, 2005
In article <djbgmb$2jqb$1@digitaldaemon.com>, Mathias says...
>
>Yes that makes it clearer for me. However, still a question:
>
># catch(Exception e)
>
>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


October 22, 2005
Ah, I think I'm beginning to understand... ;-) I was confused by the line:

# catch(Exception e)

and what it does. I didn't understand why I couldn't simply write:

# catch(e)

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


October 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:
>
># catch(Exception e)
>
>and what it does. I didn't understand why I couldn't simply write:
>
># catch(e)
>
>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


October 23, 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


October 23, 2005
"Sean Kelly" <sean@f4.ca> wrote in message news:djer01$r2t$1@digitaldaemon.com...
> 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)."

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.

>
>
> Sean
>
> 


« First   ‹ Prev
1 2