The Right Approach to Exceptions

Juan Manuel Cabo juanmanuel.cabo at gmail.com
Mon Feb 20 13:11:58 PST 2012


Yeah.. that is a problem! :-) Thanks for liking the idea, now we can
talk about the fine details!!

One way is to not let the user direct access to the associative array,
but wrap the e.info["MyDetail"] call in a nothrow function, such as
e.info("MyDetail"), and an e.hasInfo("MyDetail"), and of course:
e.addInfo("MyDetail", value) and e.allInfoNames() or something.

The nothrow function would return an empty value if not found (I fear
that it might not be of the same Variant subtype as the Variant value
was intended when present).

--jm


On 02/20/2012 05:53 PM, H. S. Teoh wrote:
> On Mon, Feb 20, 2012 at 05:31:28PM -0300, Juan Manuel Cabo wrote:
>>> ...
>>> Sure. Again, this is not advocating replacement of exception hierarchies with tables!
>>> ... 
>>>
>>> Andrei
>>>
>>
>> I think that the case of rethrowing an exception with added detail is
>> the worst enemy of clean Exception hierarchies.
> 
> Hmm. This is a valid point. Sometimes you want to add contextual details
> to an exception in order to provide the final catching code with more
> useful information. Otherwise you may end up with a chain of mostly
> redundant exception classes:
> 
> 	class UTFError : Exception {...}
> 	class LexUTFError : LexUTFError {
> 		int line, col;
> 		...
> 	}
> 	class ConfigFileParseError : LexUTFError {
> 		string cfgfile_name;
> 	}
> 
> 	auto decodeUTF(...) {
> 		...
> 		throw new UTFError;
> 	}
> 
> 	auto configLexer(...) {
> 		try {
> 			...
> 			decodeUTF(...);
> 		} catch(UTFError e) {
> 			throw new LexUTFError(...);
> 		}
> 	}
> 
> 	auto configParser(...) {
> 		try {
> 			...
> 			configLexer(...);
> 		} catch(LexUTFError e) {
> 			throw new ConfigFileParseError(...);
> 		}
> 	}
> 
> 
>> The idea of Variant[string] remedies that case without creating a new
>> exception class just for the added fields. If that case is solved,
>> then the tipical need for creating new exception types that don't
>> really aid selecting them for catching and recovery is solved too.
> [...]
> 
> However, I still hesitate about using Variant[string]. How would you
> address the following problem:
> 
> 	// Module A
> 	class MyException : Exception {
> 		this() {
> 			info["mydetail"] = ...;
> 		}
> 	}
> 
> 	// Module B
> 	auto func() {
> 		try {
> 			...
> 		} catch(MyException e) {
> 			if (e.info["mydetail"] == ...) {
> 				...
> 			}
> 		}
> 	}
> 
> If module A's maintainer renames "mydetail" to "detail", then module B
> will still compile with no problem, but now e.info["mydetail"] doesn't
> exist and will cause a runtime error at worst. At best, the catch block
> won't be able to recover from the error as it did before, because now it
> can't find the info it was looking for.
> 
> If "mydetail" had been a field stored in MyException, then module B
> would get a compile-time error, and the problem can be fixed
> immediately, instead of going unnoticed until it blows up at the
> customer's production server.
> 
> 
> T
> 



More information about the Digitalmars-d mailing list