In Python I can create my own thin exceptions (i.e. just different type for 
convenience of identification in a catch block, no added functionality) by:

class MyError(ExceptionBaseClass): pass

Even in C++ I can do just:

struct MyException: public std::exception {};

But in D:

$ cat except.d
class MyException: Exception {}
$ dmd -c except.d
except.d(1): Error: class foo.MyException cannot implicitly generate a 
default ctor when base class object.Exception is missing a default ctor

OK so I dig up /usr/include/dmd/druntime/import/object.d: which doesn't have 
a default ctor but does have a user-defined one, which then disables the 
default:

class Exception : Throwable
{
    @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t 
line = __LINE__, Throwable next = null)
}

OK fine but then I didn't get why I had to write that long constructor with 
msg, file, __FILE__ etc every time I subclassed exception, so I did:

$ cat except.d
class MyException: Exception { this() { super(""); } }
void main() { throw new MyException; }

But it didn't give the expected results:

$ dmd except.d
$ ./except
except.MyException@except.d(1)
...

... since the line number is wrong. OK so the reason is that the constructor 
which has the default arguments of __FILE__ and __LINE__ is called not at 
line 2 but at line 1 i.e. in the declaration of the subclass.

So I am forced to write out all that stuff with __FILE__ etc yet again:

$ cat except.d
class MyException: Exception { this(string msg = "", string file = __FILE__, 
size_t line = __LINE__) { super("", file, line); } }
void main() { throw new MyException; }

Then I get the desired behaviour:

$ dmd except.d
$ ./except
except.MyException@except.d(2)

This is too tortuous, and methinks a mixin is in order, and since I can't do 
anything like the C preprocessor's #X stringizing, I can't declare this as a 
mixin template but have to do a string mixin:

$ cat myexception.d
string ExceptionDeclaration(string newExceptionName, string 
baseExceptionName = "Exception")
{
    return "class " ~ newExceptionName ~ ": " ~ baseExceptionName ~ `{
        this(string msg = "", string file = __FILE__, size_t line = 
__LINE__)
            { super(msg, file, line); }
        }`;
}

void main()
{
    mixin(ExceptionDeclaration("MeaCulpa"));
    try { throw new MeaCulpa; }
    catch (MeaCulpa e) {}
    import std.conv;
    mixin(ExceptionDeclaration("MeaNeueaCulpa", "ConvException"));
    try { throw new MeaNeueaCulpa; }
    catch (MeaNeueaCulpa e) {}
    throw new MeaNeueaCulpa;
}
$ dmd myexception.d
$ ./myexception
myexception.main.MeaNeueaCulpa@myexception.d(18)
...

So, any thoughts? Any way this could be improved? Would be nice if that 
mixin got into the standard library somehow...

Reply via email to