www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - More exception classes into Phobos?

reply =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
Hi everyone.
I previously made the dub package 
https://georgy7.github.io/exceptions/exceptions.html
because many languages have the useful standard 
NotImplementedException (UnsupportedOperationException), 
ArgumentException (IllegalArgumentException), IOException. It's 
easy to catch by type.

What do you thing about to include these three exceptions in 
Phobos as the base for user exceptions.

Maybe, ArgumentException is not very suitable name for an 
exception in D, because the language has the contracts. So, 
actually, an assert will throw an Exception, when there is a bad 
argument, isn't it?
When we use IllegalArgumentException in Java at work, we actually 
mean "bad user input" in most cases. So, I would name it 
UserInputException.

Also, I saw the DIP33 https://wiki.dlang.org/DIP33
It proposes the complex class hierarchy. I have no thoughts about 
it.

Well, I just suggest to add these 3 classes in std.exception.

NotImplementedException : Exception
UserInputException : Exception
IOException : Exception

What do you think?
Mar 23 2017
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
Does anybody know if we've solved  nogc exceptions? (I haven't needed them).
If we haven't we should hold off on this.
Mar 23 2017
parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, March 23, 2017 22:39:14 rikki cattermole via Digitalmars-d 
wrote:
 Does anybody know if we've solved  nogc exceptions? (I haven't needed
 them). If we haven't we should hold off on this.
If we have any hope of solving that, it's going to depend on the built-in reference counting that hasn't been implemented yet (I believe that it's on hold while Walter works on sorting out safe issues that need to be fixed first). Other than that, AFAIK, the only solutions involve either pre-allocating exceptions (which works for some cases but is often counter-productive as far as error-reporting goes) or allocating with malloc (and that only works in isolated circumstances where everyone working on the code is well aware of the fact that the exceptions are being allocated via malloc and know how to handle that in that code base; otherwise, it's just going to cause memory leaks and safety problems). - Jonathan M Davis
Mar 23 2017
prev sibling next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, March 23, 2017 09:31:23 Георгий via Digitalmars-d wrote:
 Well, I just suggest to add these 3 classes in std.exception.

 NotImplementedException : Exception
 UserInputException : Exception
 IOException : Exception

 What do you think?
IMHO, an exception about something not being implemented is indicative of a bad design. If a class implements an interface, it should implement all of the functions of that interface, or there's a bug in the design. Similarly, if a function exists but has no implementation yet, it should use assert(0). Promoting any kind of exception for "not implemented" as being standard seems like a completely terrible idea to me. As for the others, I think that they're so generic that you might as well just use Exception. It makes a lot more sense to me to use specific exceptions for specific use cases, not general use cases. For the type to matter, it has to be something that you're going to operate on differently than you would other exception types, and that implies that they're tied to fairly specific error conditions and not anything general. So, I don't think that we should be adding more exception types to Phobos without a really good reason for it, and if we do, it's likely for something that's specific to a particular portion of Phobos rather than for general use. I think that adding new exceptions to std.exception is exactly the wrong thing to be doing. - Jonathan M Davis
Mar 23 2017
parent reply =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Thursday, 23 March 2017 at 09:48:54 UTC, Jonathan M Davis 
wrote:
 On Thursday, March 23, 2017 09:31:23 Георгий via Digitalmars-d 
 wrote:

 If a function exists but has no implementation yet, it should 
 use assert(0).
I didn't know that.
Mar 23 2017
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 23/03/2017 11:20 PM, Георгий wrote:
 On Thursday, 23 March 2017 at 09:48:54 UTC, Jonathan M Davis wrote:
 On Thursday, March 23, 2017 09:31:23 Георгий via Digitalmars-d wrote:

 If a function exists but has no implementation yet, it should use
 assert(0).
I didn't know that.
That will throw an AssertError. You should try not to catch Error's. So there still needs to be an exception of some kind.
Mar 23 2017
next sibling parent reply =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Thursday, 23 March 2017 at 10:26:38 UTC, rikki cattermole 
wrote:
 On 23/03/2017 11:20 PM, Георгий wrote:
 On Thursday, 23 March 2017 at 09:48:54 UTC, Jonathan M Davis 
 wrote:
 On Thursday, March 23, 2017 09:31:23 Георгий via 
 Digitalmars-d wrote:

 If a function exists but has no implementation yet, it should 
 use
 assert(0).
I didn't know that.
That will throw an AssertError. You should try not to catch Error's. So there still needs to be an exception of some kind.
I never supposed to catch NotImplementedException, but use it as assert(0). Well, maybe only at top level of web page rendering in a web framework to show an error message and log the stack trace.
Mar 23 2017
parent =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Thursday, 23 March 2017 at 10:36:42 UTC, Георгий wrote:
 On Thursday, 23 March 2017 at 10:26:38 UTC, rikki cattermole 
 wrote:
 On 23/03/2017 11:20 PM, Георгий wrote:
I never supposed to catch NotImplementedException,
I mean, I never meant to use it this way. So, assert(0) is much better for most of applications. But the exception may still be usable with web frameworks. https://github.com/rejectedsoftware/vibe.d/issues/666
Mar 23 2017
prev sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, March 23, 2017 23:26:38 rikki cattermole via Digitalmars-d 
wrote:
 On 23/03/2017 11:20 PM, Георгий wrote:
 On Thursday, 23 March 2017 at 09:48:54 UTC, Jonathan M Davis wrote:
 On Thursday, March 23, 2017 09:31:23 Георгий via Digitalmars-d wrote:

 If a function exists but has no implementation yet, it should use
 assert(0).
I didn't know that.
That will throw an AssertError. You should try not to catch Error's. So there still needs to be an exception of some kind.
My point was that it's bad design to be throwing an exception because something isn't implemented. If something isn't implemented, it's a bug. assert(0) is a great way to indicate that something isn't implemented yet and have the program die (like it should) if that function inadvertently gets called. I know that there are cases in Java land where folks (even the standard library in some cases) have a class implement an interface but not truly implement all of it and have the functions that aren't properly implemented throw an exception. But I don't see how that can be anything but bad design, and I don't think that we should be promoting such behavior in D's standard library. - Jonathan M Davis
Mar 23 2017
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 24/03/2017 12:09 AM, Jonathan M Davis via Digitalmars-d wrote:
 On Thursday, March 23, 2017 23:26:38 rikki cattermole via Digitalmars-d
 wrote:
 On 23/03/2017 11:20 PM, Георгий wrote:
 On Thursday, 23 March 2017 at 09:48:54 UTC, Jonathan M Davis wrote:
 On Thursday, March 23, 2017 09:31:23 Георгий via Digitalmars-d wrote:

 If a function exists but has no implementation yet, it should use
 assert(0).
I didn't know that.
That will throw an AssertError. You should try not to catch Error's. So there still needs to be an exception of some kind.
My point was that it's bad design to be throwing an exception because something isn't implemented. If something isn't implemented, it's a bug. assert(0) is a great way to indicate that something isn't implemented yet and have the program die (like it should) if that function inadvertently gets called. I know that there are cases in Java land where folks (even the standard library in some cases) have a class implement an interface but not truly implement all of it and have the functions that aren't properly implemented throw an exception. But I don't see how that can be anything but bad design, and I don't think that we should be promoting such behavior in D's standard library. - Jonathan M Davis
Nobody said that there had to be code in Phobos that used it, just a standard set of exceptions for a variety of purposes. That is what was proposed.
Mar 23 2017
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Friday, March 24, 2017 00:14:33 rikki cattermole via Digitalmars-d wrote:
 On 24/03/2017 12:09 AM, Jonathan M Davis via Digitalmars-d wrote:
 On Thursday, March 23, 2017 23:26:38 rikki cattermole via Digitalmars-d

 wrote:
 On 23/03/2017 11:20 PM, Георгий wrote:
 On Thursday, 23 March 2017 at 09:48:54 UTC, Jonathan M Davis wrote:
 On Thursday, March 23, 2017 09:31:23 Георгий via Digitalmars-d wrote:

 If a function exists but has no implementation yet, it should use
 assert(0).
I didn't know that.
That will throw an AssertError. You should try not to catch Error's. So there still needs to be an exception of some kind.
My point was that it's bad design to be throwing an exception because something isn't implemented. If something isn't implemented, it's a bug. assert(0) is a great way to indicate that something isn't implemented yet and have the program die (like it should) if that function inadvertently gets called. I know that there are cases in Java land where folks (even the standard library in some cases) have a class implement an interface but not truly implement all of it and have the functions that aren't properly implemented throw an exception. But I don't see how that can be anything but bad design, and I don't think that we should be promoting such behavior in D's standard library. - Jonathan M Davis
Nobody said that there had to be code in Phobos that used it, just a standard set of exceptions for a variety of purposes. That is what was proposed.
My point was that having an exception for something that is not implemented like Java did is a horrible design mistake and thus should not be promoted by D's standard library. Classes should not be implementing interfaces only to throw exceptions when they don't really want to be implementing some of the functionality of that interface. That's just plain bad design. If a programmer is looking to temporarily indicate that a function is unimplemented, then normally, the correct thing to do is to assert(0). And even if a programmer has a use case where it makes sense to temporarily throw an exception due to a lack of implementation rather than considering it a bug to call an unfinished function, then that's something internal to their application and thus not part of any public API and thus would not need to be standard. As for the other proposed exceptions such as IOException, I think that they're so generic as to be borderline useless. When you catch an exception, it has to be specific enough to what you're calling to actually be able to rely on what it means and actually be able to react to it differently based on its type, and "something related to I/O somewhere in the chain of functions that I just called just failed" isn't really much different from "something somewhere in the chain of functions that I just called just failed," which is basically the difference between IOException and Exception, especially if IOException is used by a bunch of different libraries all over the place, whereas if it's specific to a library that you're using, at least you can rely on where it came from and thus rely on what it means on some level. I honestly think that trying to standardize exceptions is a bad idea. They _should_ be specific to specific libraries or applications, otherwise they're not much different from just throwing Exception. - Jonathan M Davis
Mar 23 2017
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/23/2017 9:44 AM, Jonathan M Davis via Digitalmars-d wrote:
 My point was that having an exception for something that is not implemented
 like Java did is a horrible design mistake and thus should not be promoted
 by D's standard library. Classes should not be implementing interfaces only
 to throw exceptions when they don't really want to be implementing some of
 the functionality of that interface. That's just plain bad design.

 If a programmer is looking to temporarily indicate that a function is
 unimplemented, then normally, the correct thing to do is to assert(0). And
 even if a programmer has a use case where it makes sense to temporarily
 throw an exception due to a lack of implementation rather than considering
 it a bug to call an unfinished function, then that's something internal to
 their application and thus not part of any public API and thus would not
 need to be standard.

 As for the other proposed exceptions such as IOException, I think that
 they're so generic as to be borderline useless. When you catch an exception,
 it has to be specific enough to what you're calling to actually be able to
 rely on what it means and actually be able to react to it differently based
 on its type, and "something related to I/O somewhere in the chain of
 functions that I just called just failed" isn't really much different from
 "something somewhere in the chain of functions that I just called just
 failed," which is basically the difference between IOException and
 Exception, especially if IOException is used by a bunch of different
 libraries all over the place, whereas if it's specific to a library that
 you're using, at least you can rely on where it came from and thus rely on
 what it means on some level.

 I honestly think that trying to standardize exceptions is a bad idea. They
 _should_ be specific to specific libraries or applications, otherwise
 they're not much different from just throwing Exception.
Thanks for expressing this better than I could have. Over time I've found that standardized Exception types seem to become less and less useful over just using "Exception" with an appropriate message.
Mar 23 2017
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-03-23 20:47, Walter Bright wrote:

 Thanks for expressing this better than I could have. Over time I've
 found that standardized Exception types seem to become less and less
 useful over just using "Exception" with an appropriate message.
A plain Exception is completely useless, it can just as well be an assertion instead. Because it's not possible to extract any information from the exception (except for trying to parse the message which is a bad idea) resulting in not being able to act on a thrown exception. Which then results in it being pointless to catch the exception in the first place. I think it's a bad design that it's possible created instances of Exception, it should either be an abstract class or an interface. -- /Jacob Carlborg
Mar 23 2017
next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, March 23, 2017 21:34:45 Jacob Carlborg via Digitalmars-d wrote:
 On 2017-03-23 20:47, Walter Bright wrote:
 Thanks for expressing this better than I could have. Over time I've
 found that standardized Exception types seem to become less and less
 useful over just using "Exception" with an appropriate message.
A plain Exception is completely useless, it can just as well be an assertion instead. Because it's not possible to extract any information from the exception (except for trying to parse the message which is a bad idea) resulting in not being able to act on a thrown exception. Which then results in it being pointless to catch the exception in the first place. I think it's a bad design that it's possible created instances of Exception, it should either be an abstract class or an interface.
There are plenty of cases where all you care about is that something went wrong when calling a function and aren't going to do anything special depending on what went wrong. You just handle it and move on. In other cases, any exception of any kind means that you're done and exiting your program, which _is_ similar to an assertion, but the key difference is that assertions are for catching programming errors, not for reporting stuff like bad user input or that the file you're trying to operate on doesn't exist anymore. Regardless, having a generic exception type is useful. Now, there are plenty of cases where specific exception types should be used - particularly if you want to be able to have your program respond differently depending on what went wrong - but for those to be effective, they need to actually be specific, whereas most any exception type that one might consider adding to std.exception is generic and thus in pretty much the same boat as Exception. So, I see no point in general exceptions like IOException. In those cases, you might as well just use Exception. I frequently create specific exception types for libraries that I write or for pieces of libraries, because then you know where the exception came from (which can affect how you handle it), and if it's a specific type related to specific functionality within a library, then catching it specifically can really inform what exception handling code should be doing. That being said, there are plenty of cases where I'm not sure that there's much point in creating a new exception type. If it's not something that someone is going to handle differently depending on its type, and all you really care about reporting is that something went wrong, Exception is perfect for that. And in cases like D scripts, it would be overkill to be forced to create your own exception types, so it would really annoying if you couldn't create Exceptions. - Jonathan M Davis
Mar 23 2017
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 23 March 2017 at 20:48:24 UTC, Jonathan M Davis 
wrote:
 And in cases like D scripts, it would be overkill to be forced 
 to create your own exception types, so it would really annoying 
 if you couldn't create Exceptions.
Creating a new exception class is actually trivial in D, we create new types all the time without even thinking about it almost every time we hit `!`, and could be even more so with some library helpers. Catching the type when it doesn't have an outside name isn't as easy, but the randomly created types can still inherit from some base class that is caught, but the templated/generated implementation overrides various interface functions to provide more detailed, rich information (and, of course, you CAN still catch it specifically if you really wanted to).
Mar 23 2017
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-03-23 21:48, Jonathan M Davis via Digitalmars-d wrote:

 There are plenty of cases where all you care about is that something went
 wrong when calling a function and aren't going to do anything special
 depending on what went wrong. You just handle it and move on.
If you don't know that went wrong you cannot handle it. Basically the only option that is left is to abort the program. -- /Jacob Carlborg
Mar 25 2017
parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Saturday, March 25, 2017 14:17:10 Jacob Carlborg via Digitalmars-d wrote:
 On 2017-03-23 21:48, Jonathan M Davis via Digitalmars-d wrote:
 There are plenty of cases where all you care about is that something
 went
 wrong when calling a function and aren't going to do anything special
 depending on what went wrong. You just handle it and move on.
If you don't know that went wrong you cannot handle it. Basically the only option that is left is to abort the program.
In my experience, that's often not true. It could simply mean that you abort the current operation - especially in programs that act anything like servers or operate on batches of jobs. Yes, in some cases, you simply can't do anything useful if the operation failed, and you do have to abort the program, but that's not always true. It very much depends on what the program is doing. Now, if you want to respond in any manner beyond "something went wrong," you're likely going to need a more specific exception type that tells you something about what actually went wrong, but I've seen plenty of code that really didn't care what went wrong - e.g. it simply logs the error and moves on to the next operation, or it responds to the program that made the request that something went wrong and then moves on to the next request. - Jonathan M Davis
Mar 25 2017
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/23/2017 1:34 PM, Jacob Carlborg wrote:
 A plain Exception is completely useless, it can just as well be an assertion
 instead. Because it's not possible to extract any information from the
exception
 (except for trying to parse the message which is a bad idea) resulting in not
 being able to act on a thrown exception. Which then results in it being
 pointless to catch the exception in the first place.
It's a compelling point, and is the reason why there are many different exception types in Phobos. But in my experience, if an error happens and it is local enough to be dealt with specifically, it is checked for directly without needing to go through an exception. If one is far enough removed from the source of the error that one is relying on exceptions, pretty much all one can do is the binary "it worked" or "it did not work". The "why it did not work" message is then logged or sent to the user, that is the only recovery necessary. The fine grained Exception types is one of those things that sounds compelling but just doesn't seem to pay off in practice.
Mar 23 2017
parent reply Jacob Carlborg <doob me.com> writes:
On 2017-03-24 01:25, Walter Bright wrote:

 It's a compelling point, and is the reason why there are many different
 exception types in Phobos.

 But in my experience, if an error happens and it is local enough to be
 dealt with specifically, it is checked for directly without needing to
 go through an exception.
The problem is when something in the environment happens that you have no control over. Say you're program is supposed to read a file. You naturally first check if the file exists, then start reading it. What if the file exists on a USB memory which are unplugged in the middle of reading the file. If the program knows that the file suddenly doesn't exist anymore, then it can ask the user for another file, or plug the USB memory back.
 If one is far enough removed from the source of
 the error that one is relying on exceptions, pretty much all one can do
 is the binary "it worked" or "it did not work". The "why it did not
 work" message is then logged or sent to the user, that is the only
 recovery necessary.

 The fine grained Exception types is one of those things that sounds
 compelling but just doesn't seem to pay off in practice.
I don't agree. If think you have quite a narrow look at this. Example: 1. An application is internationalized. Showing a generic message in English would be pretty bad user experience. Translating the whole message directly would be a bad idea, I consider the message in an exception from a library an implementation detail. The best would be, in my opinion, to have enough information available in the exception type to build a proper translated error message for the user. 2. Another example is how the editor I use, TextMate, behaves. If I try to save a file I don't have permission to write to, it will ask for my password, basically doing the same thing as "sudo" would. 3. If I've opened a file in TextMate, then remove the directory the file is located in and then save the file in TextMate, it will show a message with the option to create the folder again. For the last two examples, if the application only got a generic Exception or FileException it would not be possible implement these features because it would know if the error is that the file doesn't exist anymore or if I don't have permission to write to the file. Talk about just providing a generic exception type. Take this error message, using std.file.copy: std.file.FileException d.d(3354): /tmp/bar/foo.txt: Permission denied It doesn't tell if the failed permission is for the source or for the target. If failed to read or failed to write. -- /Jacob Carlborg
Mar 25 2017
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/25/17 3:44 PM, Jacob Carlborg wrote:
 Take this error message, using std.file.copy:

 std.file.FileException d.d(3354): /tmp/bar/foo.txt: Permission denied

 It doesn't tell if the failed permission is for the source or for the
 target. If failed to read or failed to write.
Would be great if you submitted a PR to improve this message. -- Andrei
Mar 25 2017
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/25/2017 6:44 AM, Jacob Carlborg wrote:
 Talk about just providing a generic exception type. Take this error message,
 using std.file.copy:

 std.file.FileException d.d(3354): /tmp/bar/foo.txt: Permission denied

 It doesn't tell if the failed permission is for the source or for the target.
If
 failed to read or failed to write.
If you received an IOException instead, you're no better off. As Andrei observed, it is the message that's the problem, not the exception type. In general, I think a lot of the issues you brought up are inadequate messages, or trying to solve the problem at the wrong level of the function call hierarchy (i.e. too far up). In any case, trying to get good messages to the user is a never ending problem. No solution will be universal. It's actually a lot like writing portable code. People who have never ported code tend to make all the wrong choices in where to make things portable (see windows.h for 16 bit Windows). Crafting an exception hierarchy with no experience with nor clear idea of the problem one is trying to solve just creates a complex, useless mess. I fear that's the path we've gone down. P.S. I've worked with trying to internationalize error messages. What a mess! The foreign language string tables tend to be written by people who knew the foreign language, but had little idea of the product domain. So the messages tended to be so bad/outdated/garbled that people would just prefer the English ones.
Mar 28 2017
parent reply Jacob Carlborg <doob me.com> writes:
On 2017-03-28 11:25, Walter Bright wrote:

 If you received an IOException instead, you're no better off.
No, I agree. But I have not argued for or against a standardize exception hierarchy. I've argued that we need more specific error types (either as a hierarchy or flat structure).
 As Andrei observed, it is the message that's the problem, not the exception
type.
It's an issue with both. It's an issue with the exception type because I cannot really handle the error in any sensible way. In my opinion the error message is more of a debug aid.
 In general, I think a lot of the issues you brought up are inadequate
 messages, or trying to solve the problem at the wrong level of the
 function call hierarchy (i.e. too far up).
void main() { import std.stdio; try copy("/tmp/foo.txt", "/tmp/bar/foo.txt"); catch (FileException e) { // handle permission error? } } How should I handle a permission error in the above example? It's not possible to do so without parsing the error message. This is catching the exception as close as possible to the source (without modifying Phobos).
 In any case, trying to get good messages to the user is a never ending
 problem. No solution will be universal. It's actually a lot like writing
 portable code. People who have never ported code tend to make all the
 wrong choices in where to make things portable (see windows.h for 16 bit
 Windows). Crafting an exception hierarchy with no experience with nor
 clear idea of the problem one is trying to solve just creates a complex,
 useless mess. I fear that's the path we've gone down.
Again, I have not argued for or against an exception hierarchy. -- /Jacob Carlborg
Mar 28 2017
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Tuesday, March 28, 2017 20:07:01 Jacob Carlborg via Digitalmars-d wrote:
 On 2017-03-28 11:25, Walter Bright wrote:
 If you received an IOException instead, you're no better off.
No, I agree. But I have not argued for or against a standardize exception hierarchy. I've argued that we need more specific error types (either as a hierarchy or flat structure).
 As Andrei observed, it is the message that's the problem, not the
 exception type.
It's an issue with both. It's an issue with the exception type because I cannot really handle the error in any sensible way. In my opinion the error message is more of a debug aid.
Agreed. Error messages are just for reporting what went wrong, not for being used to decide what the code should do. That depends on the exception type (assuming that it makes sense to respond based on the type of the error), or it depends on addition information that a specific exception type provides for the program to look at and use in order to figure out how to respond.
 In general, I think a lot of the issues you brought up are inadequate
 messages, or trying to solve the problem at the wrong level of the
 function call hierarchy (i.e. too far up).
void main() { import std.stdio; try copy("/tmp/foo.txt", "/tmp/bar/foo.txt"); catch (FileException e) { // handle permission error? } } How should I handle a permission error in the above example? It's not possible to do so without parsing the error message. This is catching the exception as close as possible to the source (without modifying Phobos).
And how would you ever handle a permission error? If you don't have the permissions for the file, you don't have permissions for the file. And trying to read a file that you don't have permissions for isn't really any different from if the file didn't exist. As far as I can tell, the only difference is in what you report to the user or log, and if that's the case, simply having a better error message is all that it makes sense to do. I expect that someone could come up with a case where knowing exactly what went wrong when trying to read or write a file could be dealt with programmatically if the program knew exactly what went wrong, but in most cases, it really doesn't matter. Either the operation succeeded, or it didn't. The why doesn't matter beyond reporting it to the user or logging it. The program is going to do the same thing regardless. However, if you do want to respond to permission errors more specifically and do something differently with them than with other error cases, FileException _does_ have an errno member to get at the same information a C program would have. So, FileException is already providing additional benefit beyond what a plain Exception provides. - Jonathan M Davis
Mar 28 2017
parent Jacob Carlborg <doob me.com> writes:
On 2017-03-28 22:10, Jonathan M Davis via Digitalmars-d wrote:

 And how would you ever handle a permission error? If you don't have the
 permissions for the file, you don't have permissions for the file.
The application can ask for a password, i.e. "sudo". That is what TextMate is doing.
 And trying to read a file that you don't have permissions for isn't really any
 different from if the file didn't exist.
If the file doesn't exist the application can ask the user for another file (reading). If a directory doesn't exist it can ask the user if it should create the directory (writing a file), again, that is what TextMate is doing.
 As far as I can tell, the only
 difference is in what you report to the user or log, and if that's the case,
 simply having a better error message is all that it makes sense to do. I
 expect that someone could come up with a case where knowing exactly what
 went wrong when trying to read or write a file could be dealt with
 programmatically if the program knew exactly what went wrong, but in most
 cases, it really doesn't matter. Either the operation succeeded, or it
 didn't. The why doesn't matter beyond reporting it to the user or logging
 it. The program is going to do the same thing regardless.
But the standard library shouldn't decide that. It should just provide as much information as possible to let the developer of the application decide what to do with the error.
 However, if you do want to respond to permission errors more specifically
 and do something differently with them than with other error cases,
 FileException _does_ have an errno member to get at the same information a C
 program would have. So, FileException is already providing additional
 benefit beyond what a plain Exception provides.
Ok, I apologize for not look at exactly what FileException contains. Although I still think it's the wrong way of providing that information. In my opinion it should be it's own exception type, otherwise I would need to catch _all_ FileException exceptions even though I cannot handle them. Then look at the errno code to check if I can handle it and otherwise rethrow the exception. In addition to that I think that error originate from a call to a C function, indicated by the presence of "errno", is an implementation detail which should not be exposed outside of Phobos. It's also slightly awkward from a Windows point of view that the Unix name "errno" is used for the field. On Windows it's actually "GetLastError" that is used to populate the "errno" field not the "errno" function. It's missing a source and target field (in the case of "copy"). I don't know which files failed, and based on the error message I don't even know if it was the source or target that failed. It wouldn't be right either to add those fields to FileException because not all operations have a source and target. Yet again it shows that we need more specific exception types. In my opinion the following information should be available in the exception type for an exception to due a failed copy operation, either as a field or in the type itself: * file and line number - where the exception originated * message - generic error message for debug aid and the most simple form of error handling * source and target - the resources (file/directory) that were involved in the operation * failed resource - somehow indicating if it was the source or target that failed * operation - that operation that failed, "copy" in this case * error - what actually went wrong, "permission denied" in this case -- /Jacob Carlborg
Mar 28 2017
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 23 March 2017 at 19:47:29 UTC, Walter Bright wrote:
 Over time I've found that standardized Exception types seem to 
 become less and less useful over just using "Exception" with an 
 appropriate message.
I'm of the firm belief that exceptions should NEVER have a string message - that's a code smell. If you do it right, all the info can be determined automatically by the exception type and passed arguments and *that* is what gets printed to string. D can do a pretty amazing job at this too with templates btw.
Mar 23 2017
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/23/2017 1:45 PM, Adam D. Ruppe wrote:
 I'm of the firm belief that exceptions should NEVER have a string message -
 that's a code smell. If you do it right, all the info can be determined
 automatically by the exception type and passed arguments and *that* is what
gets
 printed to string.
The string is what gets printed to the user like: "your password has to have at least one upper case character in it" In general, such is not deducible from the type/arguments. Exceptions are not for debugging the code (that's what Errors are for), Exceptions are for informing the user that he did it wrong.
Mar 23 2017
next sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, Mar 23, 2017 at 05:28:16PM -0700, Walter Bright via Digitalmars-d wrote:
 On 3/23/2017 1:45 PM, Adam D. Ruppe wrote:
 I'm of the firm belief that exceptions should NEVER have a string
 message - that's a code smell. If you do it right, all the info can
 be determined automatically by the exception type and passed
 arguments and *that* is what gets printed to string.
The string is what gets printed to the user like: "your password has to have at least one upper case character in it" In general, such is not deducible from the type/arguments.
[...] You *could*, in theory, create very fine-grained exception types like: class PasswordInsufficientCharSetException { string category; // like "uppercase letters" int quorum; } class PasswordMinLengthException { int minLength; } try { checkPassword(pw); } catch(PasswordInsufficientCharSetException e) { writeln("Your password must have at least %d characters from the category %s", e.quorum, e.category); } catch(PasswordMinLengthException e) { writeln("Your password must be at least %d characters long", e.minLength); } catch( /* other fine-grained types */ ) { ... } The problem with this, though, is that every such fine-grained exception type becomes part of the tight coupling between the throwing code and the catching code, to the point that you end up essentially forcing the catching code (usually user code if the exception is thrown from a library) to implement what you could have already implemented in a much easier way in the throwing code instead. Essentially, having exceptions of this level of detail forces the catching code to be dependent on the implementation details of the throwing code (it has to know which set of exceptions can be thrown, and it has to know the details of the exceptions it'd like to catch, what each detail means, and what to do with it), which breaks encapsulation and is what I'd call the *real* code smell. It's a different story, of course, if the library provides a getErrorMessage(Exception e) function that hides these details away from the catching code's eyes. But in that case you might as well just include the error message in the original exception in the first place. T -- People tell me I'm stubborn, but I refuse to accept it!
Mar 23 2017
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 24 March 2017 at 00:28:16 UTC, Walter Bright wrote:
 The string is what gets printed to the user like:

    "your password has to have at least one upper case character 
 in it"

 In general, such is not deducible from the type/arguments.
Yes, of course they are. In the simplest case in D, we could do throw new ExceptionImpl!string instead of throw new Exception(string), then it is absolutely deducible from the type, since it is a part of the type by definition. That also becomes catchable independently of other exceptions (have you ever done something like `catch(Exception e) if(e.msg != "foo") throw e;`? I actually have literally done that with a crappy D library that threw an exception that I could recover from with a retry...), avoids any runtime allocation of the string, and is potentially easier to internationalize if you want to present it to the end user. That's not how I'd literally do it, but it is something we CAN do in D (and would be an improvement from the status quo, without being a hassle of hierarchies).
 Exceptions are not for debugging the code (that's what Errors 
 are for), Exceptions are for informing the user that he did it 
 wrong.
All the more reason to actually make them as informative as possible (...and likely to cut out most the irrelevant stack trace). If the user is another programmer calling your function, they ought to be able to catch and inspect the exception in order to retry. Moreover, informing the user wants to have as much info as possible. We've probably all been frustrated by in D by "Range violation" but it doesn't tell us what the value actually was. Attaching an int and sinking it into the error message ought to be trivial... and it IS, yet druntime doesn't do it. (and yes, I know that's an Error, not an Exception, but same reasoning applies) I only care about the hierarchy insomuch as I intend to catch it without catching something else from the same block of code. try { throw new RangeErrorImpl!(size_t, size_t, size_t)(x, 0, array.length); } catch(RangeError e) { // this suddenly became a billion times more useful e.toString(sink); // RangeError, 10, 0, 8 }
Mar 23 2017
parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Fri, Mar 24, 2017 at 01:44:02AM +0000, Adam D. Ruppe via Digitalmars-d wrote:
 On Friday, 24 March 2017 at 00:28:16 UTC, Walter Bright wrote:
 The string is what gets printed to the user like:
 
    "your password has to have at least one upper case character in
    it"
 
 In general, such is not deducible from the type/arguments.
Yes, of course they are. In the simplest case in D, we could do throw new ExceptionImpl!string instead of throw new Exception(string), then it is absolutely deducible from the type, since it is a part of the type by definition. That also becomes catchable independently of other exceptions (have you ever done something like `catch(Exception e) if(e.msg != "foo") throw e;`? I actually have literally done that with a crappy D library that threw an exception that I could recover from with a retry...), avoids any runtime allocation of the string, and is potentially easier to internationalize if you want to present it to the end user.
Catching an Exception by message? That sounds like horrible code smell to me. Upgrade the 3rd party library (which may change the message) and suddenly your program breaks. Bad idea. It probably makes sense for 3rd party libraries to have at least a subclass of Exception, so that you can catch errors originating from that library rather than everything in general. Beyond that, though, you're treading into implementation details territory, which is IMO a bad idea in terms of breaking encapsulation, overly tight coupling between thrower/catcher, etc.. A better way, though, is for the library to provide a retry mechanism in the first place, as part of the official API, than to rely on the caller catching an exception and identifying it.
 That's not how I'd literally do it, but it is something we CAN do in D
 (and would be an improvement from the status quo, without being a
 hassle of hierarchies).
Generally, I find that I do subclass Exception in my own code, for obvious reasons, including that since it's my own code, the rest of the code knows what to catch and what to do about it. It basically becomes an API common to code in that particular project that defines certain exception subclasses with known semantics. In 3rd party libraries, I can see a handful of exception subclasses publicly documented for that library as part of its API as stuff specific to that library that may get thrown. But I don't see how to generalize that across libraries... by that point, it will have to become so generic that it's no better than just throwing Exception with a string message.
 Exceptions are not for debugging the code (that's what Errors are
 for), Exceptions are for informing the user that he did it wrong.
All the more reason to actually make them as informative as possible (...and likely to cut out most the irrelevant stack trace). If the user is another programmer calling your function, they ought to be able to catch and inspect the exception in order to retry. Moreover, informing the user wants to have as much info as possible. We've probably all been frustrated by in D by "Range violation" but it doesn't tell us what the value actually was. Attaching an int and sinking it into the error message ought to be trivial... and it IS, yet druntime doesn't do it. (and yes, I know that's an Error, not an Exception, but same reasoning applies)
Actually, I see this as evidence *against* having RangeError in the first place. If we had stuck to throwing Exception or, in this case, Error, that would have prompted whoever wrote the bounds check code to actually write a useful error message instead of just throwing RangeError with zero additional details. (Since, after all, the exception type ought to be enough to tell the user what needs to be known.)
 I only care about the hierarchy insomuch as I intend to catch it
 without catching something else from the same block of code.
 
 
 try {
     throw new RangeErrorImpl!(size_t, size_t, size_t)(x, 0, array.length);
 } catch(RangeError e) {
     // this suddenly became a billion times more useful
     e.toString(sink); // RangeError, 10, 0, 8
 }
Except that it's not really *that* useful if you don't know what those numbers mean. They could be values taken from CPU registers in a stacktrace for all I know, which tells me nothing. Meaning that you might as well have formatted those numbers into part of the string message in the first place. A similar discussion came up some years ago, where Andrei proposed adding a Variant[string] field to Exception where the thrower can stick whatever details he likes into it. Again, though, the problem is, how would the catcher know what string keys to use to get useful info out of that field, and what the values might mean. Unless there is some documented standard, it's really not of much use. It's like receiving an XML file with no DTD. Yeah I'm sure the meaning is all there encoded in the structure somehow, but it does me no good if I don't know what it all means. Besides, even if we had Variant[string] in Exception, would people really bother to write the additional code to populate it with meaningful data? (Much less read a spec on standard key/value mappings.) Usually when I write a `throw Exception`, my mind is thinking, "yeah this is a case the code can't handle, and the user shouldn't pass to us, so just throw an Exception, get it out of the way, and let me get on to the real algorithm already." I wouldn't have the motivation to want to manually populate a hash with details that the user code might not even care about in the end. It's already kind enough on my part to actually want to use std.format to produce a message that a human reader might find helpful, like "syntax error on line 36: unexpected character 'x'". I could have just done a `throw new Exception("syntax error");` and be done with it. At least I, the human, would read that message if the Exception got thrown, but put in additional effort so that it's parseable by code? No thanks. T -- Lottery: tax on the stupid. -- Slashdotter
Mar 24 2017
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 24 March 2017 at 19:38:14 UTC, H. S. Teoh wrote:
 Catching an Exception by message? That sounds like horrible 
 code smell to me.
Yes, it is. That's why I think exception strings are an antipattern. You should be making new classes, not new strings. But, D lets us have both worlds. Consider the following: --- class MallocedException : Exception { nogc this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, file, line, next); } nogc private void freeSelf() { import core.stdc.stdlib; import core.stdc.stdio; printf("freeing\n"); free(cast(void*) this); } ~this() { freeSelf(); } } class RaisedException(string msg) : MallocedException { nogc this(string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, file, line, next); } } class RaisedExceptionDetails(string message, T...) : RaisedException!message { T args; nogc this(T args, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { this.args = args; super(file, line, next); } override void toString(scope void delegate(in char[]) sink) const { import core.internal.traits : externDFunc; alias sizeToTempString = externDFunc!("core.internal.string.unsignedToTempString", char[] function(ulong, char[], uint) safe pure nothrow nogc); char[20] tmpBuff = void; sink("RaisedException"); sink(" "); sink(file); sink("("); sink(sizeToTempString(line, tmpBuff, 10)); sink(")"); if (message.length) { sink(": "); sink(message); } foreach(idx, arg; args) { sink("\n\t["); sink(sizeToTempString(idx, tmpBuff, 10)); sink("] = "); static if(is(typeof(arg) : const(char)[])) sink(arg); else static if(is(typeof(arg) : long)) sink(sizeToTempString(arg, tmpBuff, 10)); else {} // FIXME support more } if (info) { try { sink("\n----------------"); foreach (t; info) { sink("\n"); sink(t); } } catch (Throwable) { // ignore more errors } } } } trusted nogc void raise(string msg, string file = __FILE__, size_t line = __LINE__, T...)(T args) { import core.stdc.stdlib, std.conv; enum size = __traits(classInstanceSize, RaisedExceptionDetails!(msg, T)); void* buffer = malloc(size); assert(buffer !is null); throw emplace!(RaisedExceptionDetails!(msg, T))(buffer[0 .. size], args, file, line); } void main() { raise!"my_exception"(12, "additional info", 32); } --- That raise line lets you define your string if you must, as well as *any* other data you want to pass along, with a usable, if a bit less than ideal, toString representation of it. BTW, I also went ahead and made this nogc to show that's not really so hard to do. If you catch a MallocException, just .destroy(it). Easy (at least if you control both sides of the code). Notice that there are also no Phobos imports and no user allocations at the raise site. The only thing I'd add to it is some kind of raise!YourExceptionBase overload and I'd find this pretty useful.
 It probably makes sense for 3rd party libraries to have at 
 least a subclass of Exception, so that you can catch errors 
 originating from that library rather than everything in general.
I tend to do very broad classifications. My script.d, for example, can throw three supertypes of exception: compile exception, runtime exception, and user-defined exceptions out of the script. Those are the things you'd likely catch, because each one has a different yet reasonable possible response. But, if additional info is easy to attach, I'd go ahead and do that too - there's just no reason not to when it is easy, and the catcher can then decide to get into more details if interested, or just catch one of the super classes if not.
 Actually, I see this as evidence *against* having RangeError in 
 the first place.  If we had stuck to throwing Exception or, in 
 this case, Error, that would have prompted whoever wrote the 
 bounds check code to actually write a useful error message
Come on, be realistic. We both know it would be `throw new Exception("RangeError");` with no additional data. In fact, since building strings is *significantly* more difficult than just passing arguments, building a useful string is expected to be uncommon... and it is. Grep phobos and find the majority of exception strings are static literals, even when more information could be available.
 Except that it's not really *that* useful if you don't know 
 what those numbers mean.
The class toString could also label them trivially, or, of course, you could document it for those who care (and those who don't care will just learn to ignore the noise). It is far more likely that the class toString would give useful results than throw new Exception(format(...)) since: 1) it is written once, at the class definition (or in the mixin reflection template), instead of at every throw point and 2) functions like format("") aren't available in a LOT of contexts, whereas toString(sink) from data internal to the exception can be done virtually anywhere. format("") adds a Phobos dependency, making it a no go for druntime, it adds a GC dependency, making it no go in those nogc contexts, and having to add the import can be as much of a pain as importing a exception helper template anyway. But even if it isn't labeled, you could look it up, or get used to it, or maybe even guess it from context. The point is that the info is THERE for those who want to read it. (Frankly, I prefer just segfaulting than throwing the useless RangeError as it is now, at least a core dump can be loaded up in a debugger.)
 A similar discussion came up some years ago, where Andrei 
 proposed adding a Variant[string] field to Exception where the 
 thrower can stick whatever details he likes into it.
Yeah, that's useless, it has all the same problems as format(), plus some.
 It's already kind enough on my part to actually want to use 
 std.format to produce a message that a human reader might find 
 helpful, like "syntax error on line 36: unexpected character 
 'x'". I could have just done a `throw new Exception("syntax 
 error");` and be done with it.  At least I, the human, would 
 read that message if the Exception got thrown, but put in 
 additional effort so that it's parseable by code?
Reminder: we're using D here. It is LESS effort to add info than it is to call format().
Mar 24 2017
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2017-03-24 20:38, H. S. Teoh via Digitalmars-d wrote:

 It's already kind enough on my part to actually
 want to use std.format to produce a message that a human reader might
 find helpful, like "syntax error on line 36: unexpected character 'x'".
 I could have just done a `throw new Exception("syntax error");` and be
 done with it.  At least I, the human, would read that message if the
 Exception got thrown, but put in additional effort so that it's
 parseable by code? No thanks.
If it's a specific exception type with a specific field for the line number and a field for a filename (if applicable) then it can be used in a text editor to navigate to that file and highlight the line. -- /Jacob Carlborg
Mar 25 2017
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2017-03-23 21:45, Adam D. Ruppe wrote:

 I'm of the firm belief that exceptions should NEVER have a string
 message - that's a code smell. If you do it right, all the info can be
 determined automatically by the exception type and passed arguments and
 *that* is what gets printed to string.
Exactly. -- /Jacob Carlborg
Mar 25 2017
prev sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, March 23, 2017 12:47:29 Walter Bright via Digitalmars-d wrote:
 On 3/23/2017 9:44 AM, Jonathan M Davis via Digitalmars-d wrote:
[...]
 Thanks for expressing this better than I could have. Over time I've found
 that standardized Exception types seem to become less and less useful
 over just using "Exception" with an appropriate message.
I used to think that standard exceptions made sense - I may have even argued as much in a discussion or two in this newsgroup years ago - but over time, I've come to the conclusion that they would be detrimental. I find that in most cases, either all I care about is that something went wrong (in which case, Exception is enough), or I need to know fairly specifically what went wrong so that I can respond differently based on what went wrong, and in those cases, a standard exception wouldn't be any different from Exception. It simply wouldn't provide the information that I need. It can make sense when additional information is provided (like we do with ErrnoException or SocketOSException), but that's often primarily to aid in construction of the exception type rather than really having any effect on how you handle it. What I'm increasingly on the fence about is exceptions that are specific to modules or libraries but don't really provide any additional information over what you get with Exception. We have several instances of this in Phobos (e.g. DateTimeException and URIException), and I've often done it with libraries where the entire library or a section of the library has a specific exception type. That helps indicate where the exception originates from (though stack traces obviously hepl with that), and it allows you to catch exceptions based on which library or section of a library is mad at you (which is sometimes useful), but often, it's not much different from just using Exception. To an extent, it depends on what functionality is getting its own exception, and usually, the more narrow that is, the more useful the exception type is, but ultimately, I don't know what the best approach is with such exception types. Where specific exceptions definitely make sense is stuff like FileException or SocketOSException, which provide additional information as to what went wrong - or GetOptException, where knowing what piece of functionality is mad at you is exactly what you need to know. Exception types like IOException or InvalidArgumentException simply don't tell you enough to do reliably respond to them based on what they're telling you - _especially_ if every library under the sun could be throwing them at you. At least if they were specific to a particular library, then you'd know what section of code is screaming at you, and that combined with the general type of exception might be enough to do something useful, even if the type of the exception is overly generic. - Jonathan M Davis
Mar 23 2017
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Thursday, 23 March 2017 at 16:44:51 UTC, Jonathan M Davis 
wrote:
 I honestly think that trying to standardize exceptions is a bad 
 idea. They _should_ be specific to specific libraries or 
 applications, otherwise they're not much different from just 
 throwing Exception.
With a single hierarchy it becomes difficult, but with a multiple inheritance design it makes sense to have some standards. For instance whether the exceptional situation is permanent or warrants a retry.
Mar 23 2017
parent reply =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Thursday, 23 March 2017 at 21:31:28 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 23 March 2017 at 16:44:51 UTC, Jonathan M Davis 
 wrote:
 With a single hierarchy it becomes difficult, but with a 
 multiple inheritance design it makes sense to have some 
 standards. For instance whether the exceptional situation is 
 permanent or warrants a retry.
Strong hierarchy is one of the reasons, that makes exception types less reusable. You want to use a class, but it inherits another class, that name contradicts what you want to say, throwing the exception. For instance, you want to say, that parsing goes wrong. And somebody already made ParseException, but it is derived from FileException. And your parsing doesn't relate to files or file system at all. On the other hand, the exception interfaces would be perceived like tags at a blog article. Unfortunately, I don't know D good enough. Is there the catch statements, that are active only for such exceptions, that is match multiple types (implements all enumerated interfaces) - if we want to catch a very specific case.
Mar 23 2017
parent reply =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Thursday, 23 March 2017 at 22:12:23 UTC, Георгий wrote:
 Is there the catch statements, that are active only for such 
 exceptions, that is match multiple types (implements all 
 enumerated interfaces) - if we want to catch a very specific 
 case.
https://dpaste.dzfl.pl/246264774900 No, it can't be catched by interface at all.
Mar 23 2017
parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, March 23, 2017 22:41:39 Георгий via Digitalmars-d wrote:
 On Thursday, 23 March 2017 at 22:12:23 UTC, Георгий wrote:
 Is there the catch statements, that are active only for such
 exceptions, that is match multiple types (implements all
 enumerated interfaces) - if we want to catch a very specific
 case.
https://dpaste.dzfl.pl/246264774900 No, it can't be catched by interface at all.
catch can only catch Throwable or any class derived from Throwable (normally though, you'd only catch Exception or classes derived from it). As such, you cannot catch an interface. Now, you _can_ catch a base type and then attempt to cast it to various interfaces if you want to, but that would be more or less the same as catching an exception type with an error code and having the catch block's behavior depend on the error code. These restrictions are the result of trying to avoid the C++ mess of being able to catch stuff like string or int. - Jonathan M Davis
Mar 23 2017
prev sibling parent reply =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Thursday, 23 March 2017 at 16:44:51 UTC, Jonathan M Davis 
wrote:
 Classes should not be implementing interfaces only to throw 
 exceptions when they don't really want to be implementing some 
 of the functionality of that interface. That's just plain bad 
 design.
There are the cases, when NotImplementedException is the good choice, except for the pure Exception. Currently, I am making the inter-server communication code. Now we have the situation, where there are many servers with different settings. So, in the master app I create 2 enums, say, MySettingsVariant, SlaveSettingsVariant. Then I'll rewrite the small piece of communication code, depends on their combinations. And the code will look like: if (my == X && its == Y) { } else if (my == Z && its == Y) { } else { throw new NotImplementedException(); } Well, when somebody will add a value in one of these enums and will forget to write something for the new combinations, he/she will get the meaningful stacktrace in the log. Well, I agree, it's very close to just throw Exception. The only difference in the name. But when I talked about NIE, I meant such cases in the first place (not the partial interface implementations as in some Java collections). I just say. I don't persuade to add it to Phobos.
Mar 28 2017
parent =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Tuesday, 28 March 2017 at 08:29:44 UTC, Георгий wrote:
 I meant such cases in the first place
Well, I lie, I meant both.
Mar 28 2017
prev sibling parent reply =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Thursday, 23 March 2017 at 11:09:33 UTC, Jonathan M Davis 
wrote:
 If something isn't implemented, it's a bug. assert(0) is a 
 great way to indicate that something isn't implemented yet and 
 have the program die (like it should) if that function 
 inadvertently gets called.
I don't agree. On the web, in production, even if this is a bug, the page may down, the request may down, but not entire application.
Mar 23 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Thursday, 23 March 2017 at 11:15:45 UTC, Георгий wrote:
 On Thursday, 23 March 2017 at 11:09:33 UTC, Jonathan M Davis 
 wrote:
 If something isn't implemented, it's a bug. assert(0) is a 
 great way to indicate that something isn't implemented yet and 
 have the program die (like it should) if that function 
 inadvertently gets called.
I don't agree. On the web, in production, even if this is a bug, the page may down, the request may down, but not entire application.
And more importantly, the server should return a HTTP status indicating that there was a problem and that the request should not be repeated. Just silently dying does not work as well in a bigger setting where you want other services to adapt.
Mar 23 2017
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 24/03/2017 12:29 AM, Ola Fosheim Grøstad wrote:
 On Thursday, 23 March 2017 at 11:15:45 UTC, Георгий wrote:
 On Thursday, 23 March 2017 at 11:09:33 UTC, Jonathan M Davis wrote:
 If something isn't implemented, it's a bug. assert(0) is a great way
 to indicate that something isn't implemented yet and have the program
 die (like it should) if that function inadvertently gets called.
I don't agree. On the web, in production, even if this is a bug, the page may down, the request may down, but not entire application.
And more importantly, the server should return a HTTP status indicating that there was a problem and that the request should not be repeated. Just silently dying does not work as well in a bigger setting where you want other services to adapt.
And even better, have it damn well logged!
Mar 23 2017
next sibling parent Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Thursday, 23 March 2017 at 11:56:45 UTC, rikki cattermole 
wrote:
 On 24/03/2017 12:29 AM, Ola Fosheim Grøstad wrote:
 On Thursday, 23 March 2017 at 11:15:45 UTC, Георгий wrote:
 On Thursday, 23 March 2017 at 11:09:33 UTC, Jonathan M Davis 
 wrote:
 [...]
I don't agree. On the web, in production, even if this is a bug, the page may down, the request may down, but not entire application.
And more importantly, the server should return a HTTP status indicating that there was a problem and that the request should not be repeated. Just silently dying does not work as well in a bigger setting where you want other services to adapt.
And even better, have it damn well logged!
O God, not again, please!
Mar 23 2017
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Thursday, 23 March 2017 at 11:56:45 UTC, rikki cattermole 
wrote:
 And even better, have it damn well logged!
Yes, all failed asserts should be logged with a stacktrace and the context that caused it to trigger (e.g. the initiating HTTP request that triggered the failure).
Mar 23 2017
prev sibling parent reply =?UTF-8?B?0JPQtdC+0YDQs9C40Lk=?= <httpcatharsis gmail.com> writes:
On Thursday, 23 March 2017 at 09:31:23 UTC, Георгий wrote:
 NotImplementedException : Exception
 UserInputException : Exception
 IOException : Exception
I am not sure already, NotImplementedException should be in Phobos. Something like this may be a part of vibe.d. But I still vote for two others. Especially for IOException. It's too common! It needed everywhere. Why every library, that works with streams, need to implement its own exception class for this?
Mar 23 2017
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 24/03/2017 1:11 AM, Георгий wrote:
 On Thursday, 23 March 2017 at 09:31:23 UTC, Георгий wrote:
 NotImplementedException : Exception
 UserInputException : Exception
 IOException : Exception
I am not sure already, NotImplementedException should be in Phobos. Something like this may be a part of vibe.d. But I still vote for two others. Especially for IOException. It's too common! It needed everywhere. Why every library, that works with streams, need to implement its own exception class for this?
I want to hear what Walter&Andrei have to say about memory management before we start deciding about which if any should be implemented. My suspicion is that we would need some specific logic to make the memory management quite nice here which would require logic changes. So anything done right now would be silly.
Mar 23 2017