Q: Exception design questions
Myron Alexander
someone at somewhere.com
Fri Jun 15 19:32:02 PDT 2007
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.
More information about the Digitalmars-d
mailing list