www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Sub-classing exceptions

reply Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
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...
Oct 15 2015
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, 15 October 2015 at 18:07:24 UTC, Shriramana Sharma 
wrote:
 So, any thoughts? Any way this could be improved? Would be nice 
 if that mixin got into the standard library somehow...
Writing a mixin to create a standard constructor for exception types is trivial. The problem is that you can't document code that's mixed in. So, the constructors wouldn't end up in the documentation. And while it's a bit annoying, copy-pasting the two standard constructors for exceptions is pretty trivial. /++ Params: msg = The message for the exception. file = The file where the exception occurred. line = The line number where the exception occurred. next = The previous exception in the chain of exceptions, if any. +/ this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) safe pure nothrow { super(msg, file, line, next); } /++ Params: msg = The message for the exception. next = The previous exception in the chain of exceptions. file = The file where the exception occurred. line = The line number where the exception occurred. +/ this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) safe pure nothrow { super(msg, file, line, next); } So, while this is annoying, I don't think that it's a huge problem. We probably should have better documentation on it though. However, if we were ever to get ddoc support for mixins, then we could easily write a function to use for mixing in the constructors in exception types. Heck, for exceptions that just have the two standard constructors, we could create a function to provide the code to mix in the whole type declaration. e.g. /++ My exception type. +/ mixin(genExceptionType("MyException")); But as long as you can't put ddoc on mixins or have the ddoc inside a mixin end up in the documentation, we're pretty much out of luck on that count. - Jonathan M Davis
Oct 15 2015
parent reply Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
Jonathan M Davis wrote:

 On Thursday, 15 October 2015 at 18:07:24 UTC, Shriramana Sharma
 wrote:
 So, any thoughts? Any way this could be improved? Would be nice
 if that mixin got into the standard library somehow...
Writing a mixin to create a standard constructor for exception types is trivial. The problem is that you can't document code that's mixed in. So, the constructors wouldn't end up in the documentation. And while it's a bit annoying, copy-pasting the two standard constructors for exceptions is pretty trivial.
Can't we just include the /++ +/ block within the Wysiwyg string in the mixin? Does DDoc not process mixins? Shriramana Sharma.
Oct 15 2015
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, 16 October 2015 at 01:52:12 UTC, Shriramana Sharma 
wrote:
 Jonathan M Davis wrote:

 On Thursday, 15 October 2015 at 18:07:24 UTC, Shriramana 
 Sharma wrote:
 So, any thoughts? Any way this could be improved? Would be 
 nice if that mixin got into the standard library somehow...
Writing a mixin to create a standard constructor for exception types is trivial. The problem is that you can't document code that's mixed in. So, the constructors wouldn't end up in the documentation. And while it's a bit annoying, copy-pasting the two standard constructors for exceptions is pretty trivial.
Can't we just include the /++ +/ block within the Wysiwyg string in the mixin? Does DDoc not process mixins?
ddoc doesn't process mixins. If it did, then mixing in the constructors would work just fine. But because it doesn't, mixing in the constructors only works if you don't care about them being documented, which isn't exactly good practice. - Jonathan M Davis
Oct 15 2015
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2015-10-15 20:07, Shriramana Sharma wrote:

 $ 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.
I always wondered, if the runtime can get the filename and line numbers for the backtrace, can't it get the same information where the exception was thrown?
 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); }
          }`;
 }
I think constructors should be inherited. If you declare the subclass as usual you can have a template mixin that adds the constructor. class SubException : Exception { mixin ExceptionConstructors; } -- /Jacob Carlborg
Oct 16 2015
next sibling parent reply Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
Jacob Carlborg wrote:

 On 2015-10-15 20:07, Shriramana Sharma wrote:
 
 $ 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); }
          }`;
 }
I think constructors should be inherited.
Yes the constructors are inherited, but the problem, as I illustrated, is that the inherited constructor gets the __FILE__ and __LINE__ data for the point of declaring the exception subclass, and not at the point of throwing it.
 If you declare the subclass as usual you can have a template mixin that
 adds the constructor.
 
 class SubException : Exception
 {
      mixin ExceptionConstructors;
 }
Hmmm is that in any way advantageous to what I wrote about it? Is it just that you can now add a doc-comment that DDoc can recognize? -- Shriramana Sharma, Penguin #395953
Oct 16 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/16/15 10:35 PM, Shriramana Sharma wrote:
 Jacob Carlborg wrote:
 If you declare the subclass as usual you can have a template mixin that
 adds the constructor.

 class SubException : Exception
 {
       mixin ExceptionConstructors;
 }
Hmmm is that in any way advantageous to what I wrote about it? Is it just that you can now add a doc-comment that DDoc can recognize?
You can add other members to your custom exception class. If you wanted for instance to have some specialized toString function, or extra data, you could add. With yours, only simple derived types can be created. -Steve
Oct 16 2015
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2015-10-17 04:35, Shriramana Sharma wrote:

 Hmmm is that in any way advantageous to what I wrote about it? Is it just
 that you can now add a doc-comment that DDoc can recognize?
Less ugly. You don't have to fiddle with building strings. -- /Jacob Carlborg
Oct 17 2015
parent reply Temtaime <temtaime gmail.com> writes:
Checked exceptions are a lie.
Oct 17 2015
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, 17 October 2015 at 18:00:06 UTC, Temtaime wrote:
 Checked exceptions are a lie.
??? This thread has been about declaring exception classes (many of which have exactly the same constructors and how it's annoying to have to duplicate that boilerplate). You're the first to mention anything about checked exceptions, and I don't see what it has to do with the discussion. - Jonathan M Davis
Oct 17 2015
prev sibling parent Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
Jacob Carlborg wrote:

 If you declare the subclass as usual you can have a template mixin that
 adds the constructor.
 
 class SubException : Exception
 {
 mixin ExceptionConstructors;
 }
https://github.com/D-Programming-Language/druntime/pull/1413 -- Shriramana Sharma, Penguin #395953
Oct 18 2015