Q: Exception design questions

janderson askme at me.com
Sat Jun 16 13:57:54 PDT 2007


Myron Alexander wrote:
> Hello.
> 
> I am struggling with creating an exception design for my library. I have 
> written libraries and exception mechanisms before but those libraries 
> were focused on a core problem for which all use-cases are known 
> upfront. With this library, because it is distributed, I am not in 
> control of how it is used so I am struggling to envision all possibilities.
> 
> What I have decided is to restrict the number of exceptions to just 
> those that either define a domain or declare a specific recoverable 
> exception. For my library, there will be very few recoverables, mostly 
> to do with data conflicts and database locks.
> 
> I am of the type that, as a library/framework architect, tries to 
> provide the most information possible to the developer such that the 
> developer is able to quickly pinpoint the problem and resolve it.
> 
> With that in mind, I needed a flexible exception class that could handle 
> all the information known about the state at the time of the exception. 
> I decided on a property bag that will hold all the information as 
> properties.
> 
> This is what I came up with:
> 
>> public class SqlException : Exception {
>>
>>    this (char[] msg) {
>>       super (msg);
>>    }
>>
>>    typeof(this) setSql (char[] sql) {
>>       m_propertyBag[K_SQL] = box (sql);
>>       return this;
>>    }
>>
>>    typeof(this) setProperty(T) (char[] property, T value) {
>>       m_propertyBag [property] = box (value);
>>       return this;
>>    }
>>
>>    void raise () {
>>       throw this;
>>    }
>>
>>    char[] toString () {
>>
>>       /* Format properties for output. The properties are listed one 
>> to a line
>>        * of format 'name: value'.
>>        */
>>       char[] pstr;
>>
>>       foreach (p; m_propertyBag.keys.sort) {
>>          pstr ~= "\n" ~ p ~ ": " ~ m_propertyBag[p].toString ();
>>       }
>>
>>       if (pstr.length > 0) {
>>          return msg ~ "\n" ~ pstr;
>>
>>       } else {
>>          return msg;
>>       }
>>    }
>>
>>    char[] sql () {
>>       if (K_SQL in m_propertyBag) {
>>          return unbox!(char[])(m_propertyBag[K_SQL]);
>>
>>       } else {
>>          return null;
>>       }
>>    }
>>
>>    Box[char[]] propertyBag () {
>>       return m_propertyBag;
>>    }
>>
>>    protected Box[char[]] m_propertyBag;
>>       private static const final K_SQL = "SQL";
>> }
> 
> And this is how I use it:
> 
>> (new SqlProgrammingException (
>>    "Invalid bind type. Mixing single and multiple value rows. "
>>    "The first argument type is other than Box[], thus it is "
>>    "assumed that the rest of the arguments are single value "
>>    "rows."))
>> .setSql (operation)
>> .setProperty ("ValueRow", i)
>> .setProperty ("ValueType", t)
>> .raise ();
> 
> which outputs:
> 
>> Error: Invalid bind type. Mixing single and multiple value rows. The 
>> first
>> argument type is other than Box[], thus it is assumed that the rest of 
>> the
>> arguments are single value rows.
>>
>> SQL: insert into atable values (?,?,?)
>> ValueRow: 1
>> ValueType: std.boxer.Box[]
> 
> My questions are:
> 
> 1. Is there a better way to design the exceptions?
> 2. If you have experience with this style what shortcomings did you notice.
> 3. Is there anything I have missed (conceptually or practically)?
> 4. Is there anything I should remove, or add?
> 
> Thanks ahead,
> 
> Myron.


Personally I'd try to put all those sets in the constructor, then u 
don't need to expose these to the catcher of the exception.

-Joel



More information about the Digitalmars-d mailing list