root/trunk/docsrc/errors.dd

Revision 2040, 7.8 kB (checked in by walter, 1 year ago)

typography

  • Property svn:eol-style set to native
Line 
1 Ddoc
2
3 $(SPEC_S Error Handling in D,
4
5 $(BLOCKQUOTE
6 I came, I coded, I crashed. -- Julius C'ster
7 )
8
9 All programs have to deal with errors. Errors are unexpected conditions that
10 are not part of the normal operation of a program. Examples of common errors
11 are:
12
13 $(UL
14     $(LI Out of memory.)
15     $(LI Out of disk space.)
16     $(LI Invalid file name.)
17     $(LI Attempting to write to a read-only file.)
18     $(LI Attempting to read a non-existent file.)
19     $(LI Requesting a system service that is not supported.)
20 )
21
22 <h2>The Error Handling Problem</h2>
23
24 The traditional C way of detecting and reporting errors is not traditional,
25 it is ad-hoc and varies from function to function, including:
26
27 $(UL
28     $(LI Returning a NULL pointer.)
29     $(LI Returning a 0 value.)
30     $(LI Returning a non-zero error code.)
31     $(LI Requiring errno to be checked.)
32     $(LI Requiring that a function be called to check if the previous
33         function failed.)
34 )
35
36 To deal with these possible errors, tedious error handling code must be added
37 to each function call. If an error happened, code must be written to recover
38 from the error, and the error must be reported to the user in some user friendly
39 fashion. If an error cannot be handled locally, it must be explicitly
40 propagated back to its caller.
41 The long list of errno values needs to be converted into appropriate
42 text to be displayed. Adding all the code to do this can consume a large part
43 of the time spent coding a project - and still, if a new errno value is added
44 to the runtime system, the old code can not properly display a meaningful
45 error message.
46 <p>
47
48 Good error handling code tends to clutter up what otherwise would be a neat
49 and clean looking implementation.
50 <p>
51
52 Even worse, good error handling code is itself error prone, tends to be the
53 least tested (and therefore buggy) part of the project, and is frequently
54 simply omitted. The end result is likely a "blue screen of death" as the
55 program failed to deal with some unanticipated error.
56 <p>
57
58 Quick and dirty programs are not worth writing tedious error handling code
59 for, and so such utilities tend to be like using a table saw with no
60 blade guards.
61 <p>
62
63 What's needed is an error handling philosophy and methodology such that:
64
65 $(UL
66     $(LI It is standardized - consistent usage makes it more useful.)
67     $(LI The result is reasonable even if the programmer fails
68     to check for errors.)
69     $(LI Old code can be reused with new code without having
70     to modify the old code to be compatible with new error types.)
71     $(LI No errors get inadvertently ignored.)
72     $(LI $(SINGLEQUOTE Quick and dirty) utilities can be written that still
73     correctly handle errors.)
74     $(LI It is easy to make the error handling source code look good.)
75 )
76
77 <h2>The D Error Handling Solution</h2>
78
79 Let's first make some observations and assumptions about errors:
80
81 $(UL
82     $(LI Errors are not part of the normal flow of a program. Errors
83     are exceptional, unusual, and unexpected.)
84     $(LI Because errors are unusual, execution of error handling code
85     is not performance critical.)
86     $(LI The normal flow of program logic is performance critical.)
87     $(LI All errors must be dealt with in some way, either by
88     code explicitly written to handle them, or by some system default
89     handling.)
90     $(LI The code that detects an error knows more about the error
91     than the code that must recover from the error.)
92 )
93
94 The solution is to use exception handling to report errors. All errors are
95 objects derived from abstract class Error. class Error has a pure virtual
96 function called toString() which produces a char[] with a human readable
97 description of the error.
98 <p>
99
100 If code detects an error like "out of memory," then an Error is thrown
101 with a message saying "Out of memory". The function call stack is unwound,
102 looking for a handler for the Error.
103 $(LINK2 statement.html#TryStatement, Finally blocks)
104 are executed as the
105 stack is unwound. If an error handler is found, execution resumes there. If
106 not, the default Error handler is run, which displays the message and
107 terminates the program.
108 <p>
109
110 How does this meet our criteria?
111
112 <dl>
113     <dt> It is standardized - consistent usage makes it more useful.
114     <dd> This is the D way, and is used consistently in the D
115         runtime library and examples.
116
117     <dt> The result is reasonable result even if the programmer fails
118     to check for errors.
119     <dd> If no catch handlers are there for the errors, then the
120     program gracefully exits through the default error handler
121     with an appropriate message.
122
123     <dt> Old code can be reused with new code without having
124     to modify the old code to be compatible with new error types.
125     <dd> Old code can decide to catch all errors, or only specific ones,
126     propagating the rest upwards. In any case, there is no more
127     need to correlate error numbers with messages, the correct message
128     is always supplied.
129
130     <dt> No errors get inadvertently ignored.
131     <dd> Error exceptions get handled one way or another. There is nothing
132     like a NULL pointer return indicating an error, followed by trying to
133     use that NULL pointer.
134
135     <dt> 'Quick and dirty' utilities can be written that still
136     correctly handle errors.
137     <dd> Quick and dirty code need not write any error handling code at
138     all, and don't need to check for errors. The errors will be caught,
139     an appropriate message displayed, and the program gracefully shut down
140     all by default.
141
142     <dt> It is easy to make the error handling source code look good.
143     <dd> The try/catch/finally statements look a lot nicer than endless
144     if (error) goto errorhandler; statements.
145 </dl>
146
147 How does this meet our assumptions about errors?
148
149 <dl>
150     <dt> Errors are not part of the normal flow of a program. Errors
151     are exceptional, unusual, and unexpected.
152     <dd> D exception handling fits right in with that.
153
154     <dt> Because errors are unusual, execution of error handling code
155     is not performance critical.
156     <dd> Exception handling stack unwinding is a relatively slow process.
157
158     <dt> The normal flow of program logic is performance critical.
159     <dd> Since the normal flow code does not have to check every
160     function call for error returns, it can be realistically faster
161     to use exception handling for the errors.
162
163     <dt> All errors must be dealt with in some way, either by
164     code explicitly written to handle them, or by some system default
165     handling.
166     <dd> If there's no handler for a particular error, it is handled
167     by the runtime library default handler. If an error is ignored,
168     it is because the programmer specifically added code to ignore
169     an error, which presumably means it was intentional.
170
171     <dt> The code that detects an error knows more about the error
172     than the code that must recover from the error.
173     <dd> There is no more need to translate error codes into human
174     readable strings, the correct string is generated by the error
175     detection code, not the error recovery code. This also leads to
176     consistent error messages for the same error between applications.
177 </dl>
178
179 Using exceptions to handle errors leads to another issue - how to write
180 exception safe programs. $(LINK2 exception-safe.html, Here's how).
181
182 $(COMMENT
183     $(OL
184
185     $(LI Programmers, especially inexperienced ones, tend to neglect
186     to test for the special error return value.
187     Their code just assumed the function completed successfully.
188     This leads to erratic and unpredictable
189     behavior if the function did fail.)
190
191     $(LI How each function deals with errors tends to be unique and
192     inconsistent, leading to more unintended
193     programmatic errors.)
194
195     $(LI How the error gets reported to the user tends to vary
196     arbitrarily from one program to the next and one
197     error case to the next.)
198
199     $(LI Dealing with error cases causes tedious and error-prone code
200     to be written, and so can consume much
201     programming effort.)
202
203     $(LI Error handling logic tends to be buggy because it rarely
204     gets tested by the test team.)
205
206     $(LI Functions that should have clean interfaces wind up
207     cluttering them with error return parameters and
208     cases.)
209
210     )
211 )
212
213 )
214
215 Macros:
216     TITLE=Errors
217     WIKI=Errors
Note: See TracBrowser for help on using the browser.