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
[email protected](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
[email protected](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
[email protected](18)
...
So, any thoughts? Any way this could be improved? Would be nice if that
mixin got into the standard library somehow...