The Right Approach to Exceptions
Juan Manuel Cabo
juanmanuel.cabo at gmail.com
Mon Feb 20 13:19:35 PST 2012
I forgot to add, that you could define standard details names
as string constants, and even document them in the string constant
definition.
--jm
On 02/20/2012 06:11 PM, Juan Manuel Cabo wrote:
> 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