digitalmars.D - Can we make Throwable an interface?
- Dmitry Olshansky (17/17) Dec 09 2014 Then we could use interfaces as "tags" for exceptions and catch using
- Sean Kelly (2/2) Dec 09 2014 All the stack tracing stuff is wired through Throwable, so some
- Dmitry Olshansky (8/10) Dec 09 2014 Do yYou mean that interface can't contain the code for tracing so we'd
- Lars T. Kyllingstad (7/10) Dec 10 2014 I can think of two ways to solve this:
- H. S. Teoh via Digitalmars-d (24/40) Dec 09 2014 [...]
- Dmitry Olshansky (6/30) Dec 09 2014 That's exactly what I aim to do. The question is how hard it's do in
- Kagamin (5/7) Dec 10 2014 And what if it does?
- Dmitry Olshansky (12/19) Dec 10 2014 There is no need for cartesian products.
- H. S. Teoh via Digitalmars-d (11/32) Dec 10 2014 [...]
- Kagamin (5/7) Dec 10 2014 What's the problem? When you add new functionality to std lib,
- Dmitry Olshansky (28/36) Dec 10 2014 That you miss the point of standard exception hierarchy - that is client...
- Lars T. Kyllingstad (26/37) Dec 10 2014 I think that is an excellent idea! I have looked a bit at
- Jacob Carlborg (4/6) Dec 11 2014 How does Boost implement this?
- Lars T. Kyllingstad (8/13) Dec 11 2014 Classes that contain the additional information must inherit
Then we could use interfaces as "tags" for exceptions and catch using one of many interfaces an exception has. Consider DIP33: http://wiki.dlang.org/DIP33 The 2 problems it had were: 1. enums are hard to extend for std lib, and absolutely impossible by 3rd party libraries. 2. Single hierarchy has some appeal but it doesn't allow to catch on similar classes that do not inherit from the same base class. Basically there are many ways to view similarities of excpetions and single hierarchy fails to address that. If we were to replace each class with a base interface and every Kind enum with an interface (inhereting from one or more base interfaces) then we can actually address both of these points. To druntime experts - is it hard to change Throwable to be an interface? What exactly EH system needs of Throwable? -- Dmitry Olshansky
Dec 09 2014
All the stack tracing stuff is wired through Throwable, so some duplication may need to occur if it were changed to an interface.
Dec 09 2014
09-Dec-2014 21:00, Sean Kelly пишет:All the stack tracing stuff is wired through Throwable, so some duplication may need to occur if it were changed to an interface.Do yYou mean that interface can't contain the code for tracing so we'd have to duplicate it in Error and/or Exception? But interfaces can contain final methods just fine and tracing seems like something not overridable nor public, how the whole problem area looks like? -- Dmitry Olshansky
Dec 09 2014
On Tuesday, 9 December 2014 at 18:00:05 UTC, Sean Kelly wrote:All the stack tracing stuff is wired through Throwable, so some duplication may need to occur if it were changed to an interface.I can think of two ways to solve this: 1. rename the current Throwable (to e.g. ThrowableBase) and make it inherit the new Throwable interface. 2. Move the relevant functionality to a mixin template that is used in a limited set of base exception classes. Lars
Dec 10 2014
On Tue, Dec 09, 2014 at 08:06:32PM +0300, Dmitry Olshansky via Digitalmars-d wrote:Then we could use interfaces as "tags" for exceptions and catch using one of many interfaces an exception has. Consider DIP33: http://wiki.dlang.org/DIP33 The 2 problems it had were: 1. enums are hard to extend for std lib, and absolutely impossible by 3rd party libraries. 2. Single hierarchy has some appeal but it doesn't allow to catch on similar classes that do not inherit from the same base class. Basically there are many ways to view similarities of excpetions and single hierarchy fails to address that. If we were to replace each class with a base interface and every Kind enum with an interface (inhereting from one or more base interfaces) then we can actually address both of these points.[...] I like this idea! It would also address the current messy situation with OS-specific exceptions (e.g., ErrnoException or WindowsException, or whatever it's called) vs. semantically-oriented logical exceptions (FileNotFoundException, NoAccessException, etc.). OS-specific exceptions are necessary to capture OS-specific information, but user code generally wants to catch according to more semantic / logical criteria. For example, dirEntries may fail due to permission failure, but the user is generally not interested in OS-specific error codes like errno or Windows error numbers; what is more interesting is "was this failure caused by permission error?". This problem cannot be satisfactorily resolved with a single Exception hierarchy, but it *can* be resolved by using interfaces instead of base classes. We could then have a WindowsException and a PosixErrnoException (for example), and have subclasses also implement a NoAccessException interface. Thus you have a class hierarchy based on implementation details (e.g., PosixErrorException stores errno, and WindowsException stores Windows error codes), but also an interface hierarchy based on logical categorizations of exceptions. T -- If I were two-faced, would I be wearing this one? -- Abraham Lincoln
Dec 09 2014
09-Dec-2014 21:05, H. S. Teoh via Digitalmars-d пишет:[snip]1. enums are hard to extend for std lib, and absolutely impossible by 3rd party libraries. 2. Single hierarchy has some appeal but it doesn't allow to catch on similar classes that do not inherit from the same base class. Basically there are many ways to view similarities of excpetions and single hierarchy fails to address that. If we were to replace each class with a base interface and every Kind enum with an interface (inhereting from one or more base interfaces) then we can actually address both of these points.[...] I like this idea!For example, dirEntries may fail due to permission failure, but the user is generally not interested in OS-specific error codes like errno or Windows error numbers; what is more interesting is "was this failure caused by permission error?". This problem cannot be satisfactorily resolved with a single Exception hierarchy, but it *can* be resolved by using interfaces instead of base classes. We could then have a WindowsException and a PosixErrnoException (for example), and have subclasses also implement a NoAccessException interface. Thus you have a class hierarchy based on implementation details (e.g., PosixErrorException stores errno, and WindowsException stores Windows error codes), but also an interface hierarchy based on logical categorizations of exceptions.That's exactly what I aim to do. The question is how hard it's do in runtime and if there are any critical assumptions that prevent this. -- Dmitry Olshansky
Dec 09 2014
On Tuesday, 9 December 2014 at 18:07:16 UTC, H. S. Teoh via Digitalmars-d wrote:what is more interesting is "was this failure caused by permission error?".And what if it does? You would create thousands of types and their cartesian products just to check for one of them?
Dec 10 2014
10-Dec-2014 11:20, Kagamin пишет:On Tuesday, 9 December 2014 at 18:07:16 UTC, H. S. Teoh via Digitalmars-d wrote:There is no need for cartesian products. E.g. interface ConversionException { } interface Overflow : ConversionException {} interface Underflow : ConversionException {} ... Basically enum in DIP 33 expends to a set of dervied interfaces. Anyhow enums do not allow one to catch based on them which already makes them highly unusable. -- Dmitry Olshanskywhat is more interesting is "was this failure caused by permission error?".And what if it does? You would create thousands of types and their cartesian products just to check for one of them?
Dec 10 2014
On Wed, Dec 10, 2014 at 10:47:46PM +0300, Dmitry Olshansky via Digitalmars-d wrote:10-Dec-2014 11:20, Kagamin пишет:[...] Exactly, that's what makes interfaces a good solution to this. Enums are also non-extensible, since once Phobos fixes the enum values, user code cannot extend it, even if a user-defined Exception naturally falls under one of the preexisting exception categories. Using interfaces would allow users to leverage the existing exception hierarchy instead of reinventing the square wheel every time. T -- This is not a sentence.On Tuesday, 9 December 2014 at 18:07:16 UTC, H. S. Teoh via Digitalmars-d wrote:There is no need for cartesian products. E.g. interface ConversionException { } interface Overflow : ConversionException {} interface Underflow : ConversionException {} ... Basically enum in DIP 33 expends to a set of dervied interfaces. Anyhow enums do not allow one to catch based on them which already makes them highly unusable.what is more interesting is "was this failure caused by permission error?".And what if it does? You would create thousands of types and their cartesian products just to check for one of them?
Dec 10 2014
On Tuesday, 9 December 2014 at 17:06:45 UTC, Dmitry Olshansky wrote:1. enums are hard to extend for std lib, and absolutely impossible by 3rd party libraries.What's the problem? When you add new functionality to std lib, you add an enum entry in the same pull request. 3rd party libraries define their specific exceptions and enums.
Dec 10 2014
10-Dec-2014 11:24, Kagamin пишет:On Tuesday, 9 December 2014 at 17:06:45 UTC, Dmitry Olshansky wrote:That you miss the point of standard exception hierarchy - that is client code shall not be concerned with 3-rd party exceptions of every library as long as 3rd parties use common hierarchy(s). A big problem is we can't catch based on enum or would have to rethrow. Another problem is that one hierarchy is too rigid and exceptions can be viewed from different angles (implementation-wise like WindowsException and semantic categories like PermissionException).1. enums are hard to extend for std lib, and absolutely impossible by 3rd party libraries.What's the problem?When you add new functionality to std lib, you add an enum entry in the same pull request.Aye. And every program that had final switch on it fails. There is too many opportunities to break code with that. In contrast with interfaces one explicitly has open set of possible derived interfaces.3rd party libraries define their specific exceptions and enums.Which is utter failure. If every MyFooBar library defines MyFooBar exception then the whole point of standard exceptions is moot. We degrade back to specific per library error codes, with a benefit that they are transported across stack frames. The point is to _catch_ based on common failure causes the same way across _any_ libraries. The 3rd parties are then free to provide more specific causes of say OsException or FormatException etc. which may then find their way into standard. So that all arithmetic libraries inherit Underflow and Overflow as needed in their custom exceptions, or even just use anonymous class and be done. This allows extension while keeping client's code simple. Unlike DIP33 where one cannot make FormatException grow custom enum flag for his own library _only_ thus requiring client code to _always_ deal with your custom exception explicitly. -- Dmitry Olshansky
Dec 10 2014
On Tuesday, 9 December 2014 at 17:06:45 UTC, Dmitry Olshansky wrote:Then we could use interfaces as "tags" for exceptions and catch using one of many interfaces an exception has.I think that is an excellent idea! I have looked a bit at boost::exception, and wanted for a while to incorporate something similar into DIP33. It has two important features: Firstly, it allows semantic tagging of exceptions, which is implemented in C++ by means of multiple (virtual) inheritance. Your suggestion of using interfaces for this would fit the bill nicely, I think. For interfaces that have extra functions, we could supply standard implementations of those functions as mixin templates for when users don't want to implement those functions themselves. Secondly, boost::exception allows for transport of arbitrary data to the catch site, and importantly, supplying additional data as the exception propagates up the call chain. (E.g., the lowest-level I/O function only has a file descriptor and can only provide an errno code, so the file name must be supplied at a higher level, e.g. in std.stdio.File. Furthermore, the file was opened in some context, e.g. "read image file", which may also be useful to know at the catch site.) I'm not sure what is the best way to achieve this in D, but one option is to use an (associative?) array of Variants.Consider DIP33: http://wiki.dlang.org/DIP33 The 2 problems it had were: 1. enums are hard to extend for std lib, and absolutely impossible by 3rd party libraries. 2. Single hierarchy has some appeal but it doesn't allow to catch on similar classes that do not inherit from the same base class. Basically there are many ways to view similarities of excpetions and single hierarchy fails to address that.I consider (2) the biggest problem by far. The enum solution doesn't preclude extension by subclassing – in fact, that was the main purpose of the "unknown" constant in the "Kind" enums. Lars
Dec 10 2014
On 2014-12-11 08:21, Lars T. Kyllingstad wrote:I'm not sure what is the best way to achieve this in D, but one option is to use an (associative?) array of Variants.How does Boost implement this? -- /Jacob Carlborg
Dec 11 2014
On Thursday, 11 December 2014 at 15:04:53 UTC, Jacob Carlborg wrote:On 2014-12-11 08:21, Lars T. Kyllingstad wrote:Classes that contain the additional information must inherit boost::error_info, and each exception contains a map<type_info, shared_ptr<error_info>>. We could do more or less the exact same thing in D, of course, with ErrorInfo[TypeInfo], or even Object[TypeInfo], but I think I'd prefer a non-polymorphic solution.I'm not sure what is the best way to achieve this in D, but one option is to use an (associative?) array of Variants.How does Boost implement this?
Dec 11 2014