Re: Why exceptions for error handling is so important
On Fri, 16 Jan 2015 01:01:26 + via Digitalmars-d digitalmars-d@puremagic.com wrote: On Friday, 16 January 2015 at 00:48:57 UTC, deadalnix wrote: On Thursday, 15 January 2015 at 21:29:28 UTC, Tobias Müller wrote: In a well-designed interface, every function specifies all the errors that might happen. BWAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA ! 'tis true, unfortunately implementations don't match the spec... But that ought to be machine verifiable. Shitty compilers. so human must do all machine wants from him, until that machine is pleased? i like it. and i hate humans anyway, so it's fun to see them suffering. signature.asc Description: PGP signature
Re: Why exceptions for error handling is so important
On Friday, 16 January 2015 at 00:59:34 UTC, deadalnix wrote: auto create_unique_file() { for (uint i = 0;; i++) { auto name = make_name(i); if (file_exists(name)) continue; try { create_file(name); return name: } catch(FileAlreadyExistException e) { } } } You don't need 2 interfaces, the only time when the Exception is going to fire, is if the file is created between the file_exists check and the actual creation: almost never. IMO, this example just shows that it's a bad idea to follow the exceptions are for exceptional circumstances only mantra too strictly. The call to `file_exists()` serves no other purpose than to make the exception truly exceptional, otherwise it's completely superfluous (well, aside from performance concerns, but these are implementation details). Simply leave it out and only rely on the exception, it really isn't evil.
Re: Why exceptions for error handling is so important
IMO, this example just shows that it's a bad idea to follow the exceptions are for exceptional circumstances only mantra too strictly. The call to `file_exists()` serves no other purpose than to make the exception truly exceptional, otherwise it's completely superfluous (well, aside from performance concerns, but these are implementation details). Simply leave it out and only rely on the exception, it really isn't evil. 1. Exception are too slow 2. They're used for exceptional cases only, they're fast enough for this 1. But look here, my file handling code might very well throw an exception, if the file already exists. -- Use of a very slow operation, probably involving a spinning disk, at least a system call, to argue that exceptions are too slow does not convince me, sorry.
Re: Why exceptions for error handling is so important
On Thursday, 15 January 2015 at 19:19:22 UTC, Marc Schütz wrote: When you say copy, I expect that to mean do a bitwise copy and call the postblit. Postblit is obviously not desired here, but merely doing the bitwise copy is enough. That's a move, because afterwards the original location isn't usable anymore (the originating thread is dead). Ah, yes, I was not thinking current D compiler internals, just it is implementable. :) But I think cheap/efficient exceptions are important since API consistency makes it easier to write correct code. Single inheritance makes it difficult to use exceptions with multiple libraries since they want their own root exception. A solid ontology that outlines the most common qualities you want to filter would help a lot. Maybe also a classification mechanism that allows you to group exceptions from multiple libraries. E.g.: classify library1.EntityNotFound, library2.LookupFailure as NotFound;
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 17:45:28 UTC, deadalnix wrote: On Wednesday, 14 January 2015 at 11:17:52 UTC, Marc Schütz wrote: Your claims: - Exceptions are for I have no idea what to do about this situations. - exceptions for control flow [...] makes for very unreadable/unmaintainable code Ola's answer directly addresses these claims and provides a counter-example (in the last paragraph), which I happen to agree with. = Not a strawman. Being precise is important. The example presented (ie throwing a exception signaling a http code) is a good one and never contradict what I said. It is an example I have no idea what to do about this. The code throwing the exception is faced with a situation where it cannot continue (assuming this code is expected to generate a webpage or something like that) but at the same time, is not in a position to perform the custom http so it is bailing out. It is signaling to higher level I would have liked to return this http code, but have no idea how to do so and so I'm giving up. Now I see how you can consider this as a control flow, but it is vastly different from usual control flow (loops, branches, calls, ...). It is vastly different. You have no idea where you send your program into. In fact, you may not even be in in the framework that can make sens of this exception, you have no idea. Conversely, the framwork that is catching this exception have no idea where it came from, and it do not care either. It simply know that the page failed to render and that instead it should return a specific error code. Indeed I was assuming that the code handling the HTTP request (controller in MVC terms) is aware of the framework, because I don't think it's common to have exchangeable server frameworks for any given web application. Given that, the use of exceptions becomes part of the framework's API. Furthermore, the code also has a very clear idea of how to handle the situation, namely instructing the framework to return a specific error code. That is not giving up, in my eyes, but actually the opposite, to answer a specific request (e.g. GET /non-existant-file.txt) with the response prescribed by the protocal (e.g. 404 Not found). It could just as well have called a helper `respondWith404()` provided by the framework to set a flag somewhere and return to the framework in order to it act accordingly. It's just that the mechanism of using an exception seems more convenient (but of course, de gustibus...). Now, for a more generic library, you are right that using exceptions in this way is not a good idea. The crucial difference is IMO that in an MVC framework the application code is the one down the stack, while in many other applications it is further up the stack. Therefore, the use of exceptions (which always propagate upwards) have to be assessed differently.
Re: Why exceptions for error handling is so important
On Thursday, 15 January 2015 at 21:28:59 UTC, H. S. Teoh via Digitalmars-d wrote: Unless, of course, the *purpose* of the program is specifically to deal with problem situations -- in which case, you wouldn't be using exceptions to indicate those situations, you'd treat them as normal input instead. You wouldn't be using try/throw/catch, but normal flow-control constructs. But for almost every environmental error, there's a use case where it is normal or at least expected. That means, you have to have two versions of every function, one that throws and one that uses normal flow control. Example: Creating a file: Throws if already exists. Creating a unique filename: Create file.1.exp Create file.2.exp Create file.3.exp ... until it succeeds. Here failure is expected and normal, still trial/error is the only option because a querying the file first is not safe. How can I (as the implementer of the Create file function) decide if a failure is actually expected or not? I can't, because I cannot foresee every use case of the function. *Especially* with environmental errors that caller has to decide what's an error and what not. You cannot just require certain environmental preconditions, because they can change unexpectedly.
Re: Why exceptions for error handling is so important
On Thursday, 15 January 2015 at 21:48:25 UTC, Tobias M wrote: But for almost every environmental error, there's a use case where it is normal or at least expected. That means, you have to have two versions of every function, one that throws and one that uses normal flow control. Exactly. Just think about validation of user input. Is it a service or is it a test of environmental failure? Oh, it is a service when you validate the input with a regexp, but if the database does the validation against the db schema then it is an environmental failure. Since it is normal for users to make mistakes we now have to do double work to satisfy the no-exceptions-regime. Or take a XML validation service. Is failure to validate not part of normal operation, yes it is. So we cannot use exceptions. But if we retrieve the XML from a XML database, then failure to validate is not normal operation, so then we can use exceptions in the validator. From a computational view the validators are doing the same work, that means the implementation should be the same too. How can I (as the implementer of the Create file function) decide if a failure is actually expected or not? I can't, because I cannot foresee every use case of the function. Reminds me of people who say that you should always test if a file exists before you open it. But to do that correctly you would have to put a lock on the file system since the file could be deleted between the test and the opening... And again, we are doing double work. Great. With this regime in place no overhead exceptions for normal operations creates a lot of overhead since the computer have to do double work to avoid exceptions when using libraries and frameworks. No wonder people don't want to use exceptions in C++.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 12:15:03 UTC, Ola Fosheim Grøstad wrote: On Wednesday, 14 January 2015 at 11:20:49 UTC, Marc Schütz wrote: Without addressing anything else: You want moving here, not copying. How can you move a value, it has no identity? When you say copy, I expect that to mean do a bitwise copy and call the postblit. Postblit is obviously not desired here, but merely doing the bitwise copy is enough. That's a move, because afterwards the original location isn't usable anymore (the originating thread is dead).
Re: Why exceptions for error handling is so important
On Thu, Jan 15, 2015 at 09:01:35PM +, via Digitalmars-d wrote: On Monday, 12 January 2015 at 20:53:04 UTC, Walter Bright wrote: On 1/12/2015 10:06 AM, Tobias Müller wrote: On Mon, Jan 12, 2015 at 05:22:26PM +, Adam D. Ruppe via Digitalmars-d wrote: Yeah, exceptions are supposed to be ... well, *exceptions*, rather than the norm. :-) If you're using exceptions to do flow control, you're doing something wrong. But what's exceptional for you is normal for me. It's not a subjective truth, it's an objective fact. If code is throwing exceptions as part of its normal operation, it is designed wrong. But what this means that exceptions should only ever be used for catching programming errors, some kind of soft assertions. No, that's wrong. Programming errors are caught by assertions, not exceptions. Exceptions are used for handling unexpected *environmental* circumstances, such as a file that should be there but isn't, a disk that should be able to store data but happens to be full, a network server you need to talk to that ought to be present but is down for some reason, data received from a helper program that ought to have a certain format but for whatever reason sent malformed output instead. It also means, that exceptions should only be thrown, but never be actually handled, because by handling it you would admit that it's actually normal operation. This is not what I call error *handling*. Huh?! Handling unexpected circumstances is hardly normal operations, it's making the program deal gracefully with problem situations in the environment that normally shouldn't occur. If the default server is down, switch to a backup server. If a required file is missing, fall back to a backup copy, or give up, file a log message, and clean up any resources properly before exiting. Etc.. That doesn't change the fact that problem situations should not be the norm -- if it is, then you're doing something wrong. A server shouldn't be constantly down. A required file shouldn't be mysteriously missing every other hour. Etc.. Unless, of course, the *purpose* of the program is specifically to deal with problem situations -- in which case, you wouldn't be using exceptions to indicate those situations, you'd treat them as normal input instead. You wouldn't be using try/throw/catch, but normal flow-control constructs. T -- It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 00:51:25 UTC, Walter Bright wrote: Perhaps I misunderstand, but given A calls B calls C, A = B = C and C detects an error, and A knows what to do with the error. B then becomes burdened with checking for the error, invoking some sort of cleanup code, and then propagating it. There's another reason why this is not that bad (under the assumption that errors are _not_ only used for premature termination): The meaning of an error ist in most cases only clear in combination with the function call. With every step in the call stack you lose information about the error and the handling becomes more difficult. In a well-designed interface, every function specifies all the errors that might happen. And by this I mean a meaningful set of errors that is useful for the caller, not just the union of all errors resulting from the implementation. Simply propagating errors is not really an option in that case, because higher-level functions often also (should) have higher-level errors (the lower-level root-error should still be available though). Some random example: Some function needs some configuration from a file, but has no permission - signals a permission error. But it doesn't make sense for C to just propagate a permission error. Instead it should signal a configuration error and store the permission error as the cause of that configuration error.
Re: Why exceptions for error handling is so important
On Thursday, 15 January 2015 at 21:29:28 UTC, Tobias Müller wrote: In a well-designed interface, every function specifies all the errors that might happen. BWAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA !
Re: Why exceptions for error handling is so important
On Thursday, 15 January 2015 at 21:48:25 UTC, Tobias M wrote: Example: Creating a file: Throws if already exists. Creating a unique filename: Create file.1.exp Create file.2.exp Create file.3.exp ... until it succeeds. Here failure is expected and normal, still trial/error is the only option because a querying the file first is not safe. How can I (as the implementer of the Create file function) decide if a failure is actually expected or not? I can't, because I cannot foresee every use case of the function. *Especially* with environmental errors that caller has to decide what's an error and what not. You cannot just require certain environmental preconditions, because they can change unexpectedly. auto create_unique_file() { for (uint i = 0;; i++) { auto name = make_name(i); if (file_exists(name)) continue; try { create_file(name); return name: } catch(FileAlreadyExistException e) { } } } You don't need 2 interfaces, the only time when the Exception is going to fire, is if the file is created between the file_exists check and the actual creation: almost never.
Re: Why exceptions for error handling is so important
On Friday, 16 January 2015 at 00:48:57 UTC, deadalnix wrote: On Thursday, 15 January 2015 at 21:29:28 UTC, Tobias Müller wrote: In a well-designed interface, every function specifies all the errors that might happen. BWAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA ! 'tis true, unfortunately implementations don't match the spec... But that ought to be machine verifiable. Shitty compilers.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 20:53:04 UTC, Walter Bright wrote: On 1/12/2015 10:06 AM, Tobias Müller wrote: On Mon, Jan 12, 2015 at 05:22:26PM +, Adam D. Ruppe via Digitalmars-d wrote: Yeah, exceptions are supposed to be ... well, *exceptions*, rather than the norm. :-) If you're using exceptions to do flow control, you're doing something wrong. But what's exceptional for you is normal for me. It's not a subjective truth, it's an objective fact. If code is throwing exceptions as part of its normal operation, it is designed wrong. But what this means that exceptions should only ever be used for catching programming errors, some kind of soft assertions. It also means, that exceptions should only be thrown, but never be actually handled, because by handling it you would admit that it's actually normal operation. This is not what I call error *handling*.
Re: Why exceptions for error handling is so important
On Thursday, 15 January 2015 at 19:37:33 UTC, Marc Schütz wrote: Now, for a more generic library, you are right that using exceptions in this way is not a good idea. The crucial difference is IMO that in an MVC framework the application code is the one down the stack, while in many other applications it is further up the stack. Therefore, the use of exceptions (which always propagate upwards) have to be assessed differently. FWIW, although the framework I use provides exceptions for returning HTTP status, I don't use them. I have my own super-class request handler that captures everything so that I can reformulate caught exceptions into something that fits the REST api I expose, which have to fit what browser support (like IE9)... The only problem I see is if the exception type system lacks an ontology that the framework can rely upon.E.g. that a function pass the exception on, but mistakenly executes an action because it makes a classification mistake. But that is more a problem with having an inadequate/unspecified/fuzzy exception classification mechanisms... The language could define an ontology that allows you to express pass through unknown, not a failure, no rollback or similar as part of the exception type. Finding the exact right semantics is perhaps tricky, but also an area where there is room for practical innovation.
Re: Why exceptions for error handling is so important
On Wed, Jan 14, 2015 at 3:16 AM, Paulo Pinto via Digitalmars-d digitalmars-d@puremagic.com wrote: On Wednesday, 14 January 2015 at 10:37:31 UTC, Atila Neves wrote: That post, to me, only reinforces how much better using exceptions is. Atila They posted recently a blog post about error handling in Go. https://blog.golang.org/errors-are-values -- Paulo Agree, on the other hand is another example of the mindset. It is interesting to me that as people come up with ways to make error-code handling better it starts looking very much like exceptions.
Re: Why exceptions for error handling is so important
On Wed, Jan 14, 2015 at 10:56:39AM -0800, Jeremy Powers via Digitalmars-d wrote: On Wed, Jan 14, 2015 at 3:16 AM, Paulo Pinto via Digitalmars-d digitalmars-d@puremagic.com wrote: On Wednesday, 14 January 2015 at 10:37:31 UTC, Atila Neves wrote: That post, to me, only reinforces how much better using exceptions is. Atila They posted recently a blog post about error handling in Go. https://blog.golang.org/errors-are-values -- Paulo Agree, on the other hand is another example of the mindset. It is interesting to me that as people come up with ways to make error-code handling better it starts looking very much like exceptions. +1. T -- Meat: euphemism for dead animal. -- Flora
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 11:17:52 UTC, Marc Schütz wrote: Your claims: - Exceptions are for I have no idea what to do about this situations. - exceptions for control flow [...] makes for very unreadable/unmaintainable code Ola's answer directly addresses these claims and provides a counter-example (in the last paragraph), which I happen to agree with. = Not a strawman. Being precise is important. The example presented (ie throwing a exception signaling a http code) is a good one and never contradict what I said. It is an example I have no idea what to do about this. The code throwing the exception is faced with a situation where it cannot continue (assuming this code is expected to generate a webpage or something like that) but at the same time, is not in a position to perform the custom http so it is bailing out. It is signaling to higher level I would have liked to return this http code, but have no idea how to do so and so I'm giving up. Now I see how you can consider this as a control flow, but it is vastly different from usual control flow (loops, branches, calls, ...). It is vastly different. You have no idea where you send your program into. In fact, you may not even be in in the framework that can make sens of this exception, you have no idea. Conversely, the framwork that is catching this exception have no idea where it came from, and it do not care either. It simply know that the page failed to render and that instead it should return a specific error code.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 07:49:09 UTC, Ola Fosheim Grøstad wrote: Then you can't catch by super class. This is not going to fly. I said value. Use bitmasks. Class hierarchies don't work very well. Once again, no specifics. You write that paragraph like there is some logical links between elements in it, but there is none. If you cannot follow the logic... Where did you get lost? I was not lost. I know how to recognize a non sequitur when I read one. The only things that is sure here is that it is going to make the non exception path slower. Without specific we can say anything else than that. ? You essentially have two options: 1. A single branch on return. 2. Multiple return paths. 2a) returning to the calling function 2b) using a landing pad (current solution) It's a good thing that you can do all of these in D already. It won't help with register pressure. Having a pointer to an exception object in a register is equivalent to having a pointer to a TLS memory area in a register. TLS is in a register already. You only need this when you are using static TLS variable, which is not that common in practice. The change would makes this required all over the place. it can be optimized away so you don't need TLS if you don't span over non-D code. Without specifics, it is another instance of the sufficiently smart compiler running gag. This does not take a very smart compiler. You can use heuristics, such as ones using the function signature. It is a known fact that a sufficiently smart compiler will use heuristic. It is also fairly obvious that this heuristic will use function signature. You don't make things faster by making the calling convention easier. There is chance that this is gonna fly any better than a flat iron. ? Of course you make it faster by allowing the compiler to use it's own calling conventions. Making a new calling convention is not going to magically make things faster. If the calling convention need to do more, it is certainly going to make things slower. Hopefully, function calls are not common at all, so that shouldn't be a problem.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 17:45:28 UTC, deadalnix wrote: It is an example I have no idea what to do about this. The code throwing the exception is faced with a situation where it cannot continue (assuming this code is expected to generate a webpage or something like that) but at the same time, is not in a position to perform the custom http so it is bailing out. No, 201 means success, resource created, and 409 means that it was not carried out because of conflict in the request. However, these may be meaningful responses to the client based on the input, like 204 no content. So it is output. Throwing an exception is just an efficient way to abort all resources and queries that may be in progress and return a status to the client in a clean fashion when you don't need a text body. Just a mechanism. And it makes sense if used consistently.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 17:53:54 UTC, deadalnix wrote: Once again, no specifics. How is a bitmask (e.g. a set) not specific? I was not lost. I know how to recognize a non sequitur when I read one. Then you should also be able to explain where you got lost. 1. A single branch on return. 2. Multiple return paths. 2a) returning to the calling function 2b) using a landing pad (current solution) It's a good thing that you can do all of these in D already. This is about what the compiler does, not what you can do in D. So no. You cannot have multiple return paths (like returning to the returnaddress+OFFSET) or branch implicitly based on the carry flag upon return. You only need this when you are using static TLS variable, which is not that common in practice. The change would makes this required all over the place. That's the point. To have a buffer in TLS so that you don have to do transient heap allocations (allocation directly followed by deallocation of same object). Making a new calling convention is not going to magically make things faster. If the calling convention need to do more, it is certainly going to make things slower. One needs a calling convention to ensure that the backend puts the exception signal in the right register or to do offset return. Or to free up more registers. Haskell has a register heavy calling convention to speed up Haskell code. So it is not certainly going to make things slower. Clearing a flag/register will most likely fill in a bubble in the pipeline. A predicted non-branching branch instruction is fairly cheap. Hopefully, function calls are not common at all, so that shouldn't be a problem. ?
Re: Why exceptions for error handling is so important
On Tue, Jan 13, 2015 at 8:26 PM, deadalnix via Digitalmars-d digitalmars-d@puremagic.com wrote: On Wednesday, 14 January 2015 at 02:40:20 UTC, Jeremy Powers via Digitalmars-d wrote: http://www.artima.com/intv/handcuffs.html The best sum up of checked exception you'll find. False. Unless you mean 'the best sum up of the problems people have with checked exceptions' - it gives a good description of how use of checked exceptions often goes wrong. Full stop. I made that mistake myself various time, so I can talk from experience here. This is a completely wrong mindset. If people have problem with checked exception, then there IS a problem with checked exception, not people. You won't be able to change people, so you'd better focus on changing checked exceptions. You are completely right. Let me rephrase: The article gives a good overview of the places where checked exceptions are weak, and where people have problems with them. The things it mentions have best-practice work arounds (or are actually features), and do not invalidate all the usefulness that checked exceptions provide. It would be great if there were some other scheme instead of checked exceptions, or a slightly different design of them, if it gave me the same advantages without the issues. Unfortunately I have not seen one yet.
Re: Why exceptions for error handling is so important
Just to be clear on this. Sandy Bridge and later have 16 x 256 bits registers. There is really no reason for an optimizing compiler to not just stuff the whole exception value into 1 or 2 of those in most cases where it has full control. In the rare case where that is not enough, or possible, stuff it into a fixed TLS buffer (or a similar arrangement) and clear a signal value in that buffer when the exception is caught.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 00:24:41 UTC, Ola Fosheim Grøstad wrote: On Tuesday, 13 January 2015 at 23:58:53 UTC, deadalnix wrote: http://dlang.org/phobos/core_thread.html#.Thread.join I don't see the problem. I'm suggesting value semantics, it can be copied. Without addressing anything else: You want moving here, not copying.
Re: Why exceptions for error handling is so important
That post, to me, only reinforces how much better using exceptions is. Atila They posted recently a blog post about error handling in Go. https://blog.golang.org/errors-are-values -- Paulo
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 20:58:43 UTC, deadalnix wrote: On Tuesday, 13 January 2015 at 19:36:31 UTC, Marc Schütz wrote: On Monday, 12 January 2015 at 23:01:53 UTC, Ola Fosheim Grøstad wrote: On Monday, 12 January 2015 at 22:06:32 UTC, deadalnix wrote: No, Exception are a bail out mechanism. It is the, I have no idea what to do about this mechanism. The way it is done in C++, yes. If you put aside performance concerns, exceptions for control flow also tend to make many code path implicit and makes for very unreadable/unmaintainable code. But exceptions are control flow. There is no such thing as normalized control flow, all state changes implies control flow. Think in terms of a state machine. You could just remove all variables and only have a big state machine (assuming finite dimensions). Every single state transition implies flow of control. The control flow you see in the source code is just the programmer's rendition of control flow. Exceptions is a mechanism for getting cluttering resolution out of that rendition to make the code more readable and maintainable. The goal is to retain the meat of the computation and remove the noise. Or to put it differently, there are many ways to write the same function. Good use of exceptions removes the clutter and leaves the things you care about visible. It's a mechanism, not a moral issue or a religion. So there is nothing wrong with throwing HTTPStatus(409) or HTTPStatus(201), even though it returns state to the environment. If that means the code is more maintainable and more likely to be correct, then that is good use of the mechanism. I usually don't do this, but I really need to post a +1 here: +1 Too bad you chose to do this on a bad strawmman. Your claims: - Exceptions are for I have no idea what to do about this situations. - exceptions for control flow [...] makes for very unreadable/unmaintainable code Ola's answer directly addresses these claims and provides a counter-example (in the last paragraph), which I happen to agree with. = Not a strawman.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 10:37:31 UTC, Atila Neves wrote: That post, to me, only reinforces how much better using exceptions is. Atila They posted recently a blog post about error handling in Go. https://blog.golang.org/errors-are-values -- Paulo Agree, on the other hand is another example of the mindset. -- Paulo
Re: Why exceptions for error handling is so important
On Tue, 13 Jan 2015 11:56:00 + Paulo Pinto via Digitalmars-d digitalmars-d@puremagic.com wrote: They posted recently a blog post about error handling in Go. https://blog.golang.org/errors-are-values great article! it clearly shows how NOT to do error handling and why exceptions are far superior. signature.asc Description: PGP signature
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 11:20:49 UTC, Marc Schütz wrote: Without addressing anything else: You want moving here, not copying. How can you move a value, it has no identity? (Not that I really care much for Thread.join(). How many actually use it?)
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 23:58:53 UTC, deadalnix wrote: http://dlang.org/phobos/core_thread.html#.Thread.join I don't see the problem. I'm suggesting value semantics, it can be copied. When you are in the catch, you are not unwinding anymore. You could indeed loose chaining to be able to reuse the memory, that is not what is slow when it come to exception, so it won't make it fast. You can't have chaining with this scheme...? But since you can only have one instance it has to be initialized with value semantics. It's a small constraint. Not using regular Itanium-style unwinding will make it potentially faster. Using TLS makes it possible to propagate over non-D code or code where the register pressure is high, it can be optimized away so you don't need TLS if you don't span over non-D code. 1. So that you can mark a non-D function with @checkexception and allow it to both cast D-exceptions and propagate D-exceptions. Empty hand waving, not not addressing the point. Who are you waving at? Non D functions can cast by setting the TLS memory to an exception value, then do a regular return. The D function that called the non-D function will check TLS memory to see if there is an exception in flight. Skipping 4 and 5, you obviously didn't though that through. ? What you propose in point 1 - 3 is weak at best. You haven't put serious effort thinking about what you are proposing, so there is no reason anyone should spend any serious effort criticizing it. Then don't bother. If your point regarding point 4 was that it would limit cross compiler linking, then yes. And that would be intentional, since it is far too soon to standardize D at that level. It just prevents experimentation and performance gains. If your point regarding point 5 is that it would be too limiting, well then you would need to differentiate between D and C entrypoints to D functions to overcome the problem. That's possible, but IMO not worth it.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 00:38:21 UTC, Walter Bright wrote: On 1/11/2015 2:48 AM, Walter Bright wrote: However, if exceptions are thrown for errors instead, the programmer has to deliberately add code if he wishes to ignore the error. Interesting that this article just appeared: https://blog.golang.org/errors-are-values by Rob Pike on error handling in Go. He concludes with: But remember: Whatever you do, always check your errors! Which sums up why exceptions are better! But checked exceptions are definitely not.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 02:40:20 UTC, Jeremy Powers via Digitalmars-d wrote: http://www.artima.com/intv/handcuffs.html The best sum up of checked exception you'll find. False. Unless you mean 'the best sum up of the problems people have with checked exceptions' - it gives a good description of how use of checked exceptions often goes wrong. Full stop. I made that mistake myself various time, so I can talk from experience here. This is a completely wrong mindset. If people have problem with checked exception, then there IS a problem with checked exception, not people. You won't be able to change people, so you'd better focus on changing checked exceptions.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 20:07:17 UTC, deadalnix wrote: On Sunday, 11 January 2015 at 13:06:27 UTC, Dicebot wrote: What is your opinion of approach advertised by various functional languages and now also Rust? Where you return error code packed with actual data and can't access data without visiting error code too, compiler simply won't allow it. Rust has an approach very similar to exception, but they do not unwind and trash the whole task instead. Under the hood, it is exception, but tend to be faster as you don't go through the landing pad/personality function dance, but do not fundamentally differ. I think it does unwind (i.e. call destructors), but the exception cannot be called and ultimately will lead to task failure. At least this was the case some time ago, maybe it has changed?
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 01:37:46 UTC, deadalnix wrote: On Wednesday, 14 January 2015 at 00:24:41 UTC, Ola Fosheim Grøstad wrote: I don't see the problem. I'm suggesting value semantics, it can be copied. Then you can't catch by super class. This is not going to fly. I said value. Use bitmasks. Class hierarchies don't work very well. You can't have chaining with this scheme...? But since you can only have one instance it has to be initialized with value semantics. It's a small constraint. You write that paragraph like there is some logical links between elements in it, but there is none. If you cannot follow the logic... Where did you get lost? The only things that is sure here is that it is going to make the non exception path slower. Without specific we can say anything else than that. ? You essentially have two options: 1. A single branch on return. 2. Multiple return paths. 2a) returning to the calling function 2b) using a landing pad (current solution) It won't help with register pressure. Having a pointer to an exception object in a register is equivalent to having a pointer to a TLS memory area in a register. TLS is in a register already. it can be optimized away so you don't need TLS if you don't span over non-D code. Without specifics, it is another instance of the sufficiently smart compiler running gag. This does not take a very smart compiler. You can use heuristics, such as ones using the function signature. You don't make things faster by making the calling convention easier. There is chance that this is gonna fly any better than a flat iron. ? Of course you make it faster by allowing the compiler to use it's own calling conventions.
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 00:05:31 UTC, Walter Bright wrote: On 1/12/2015 3:17 PM, deadalnix wrote: On Monday, 12 January 2015 at 22:17:57 UTC, Walter Bright wrote: Yes, it does. Returning an int in EAX now becomes returning a pair [EAX,EDX]. It is not that big of a deal, EDX is a trash register anyway if memory serve, but then, it become very bad when it do not fit in register anymore. Returning a slice, for example, already consumes EAX and EDX. Adding an error code pushes that into returning via a pointer to a stack temporary. There are techniques to mitigate that. For example, Rust is smart enough to encode the not-present state for pointers as a NULL pointer (Rust pointers are non-null). If an error code needs to be returned, it can be encoded as a misaligned pointer (if you're feeling adventurous). Don't know whether Rust does the latter, though. Of course, these things have costs of their own.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 23:01:53 UTC, Ola Fosheim Grøstad wrote: On Monday, 12 January 2015 at 22:06:32 UTC, deadalnix wrote: No, Exception are a bail out mechanism. It is the, I have no idea what to do about this mechanism. The way it is done in C++, yes. If you put aside performance concerns, exceptions for control flow also tend to make many code path implicit and makes for very unreadable/unmaintainable code. But exceptions are control flow. There is no such thing as normalized control flow, all state changes implies control flow. Think in terms of a state machine. You could just remove all variables and only have a big state machine (assuming finite dimensions). Every single state transition implies flow of control. The control flow you see in the source code is just the programmer's rendition of control flow. Exceptions is a mechanism for getting cluttering resolution out of that rendition to make the code more readable and maintainable. The goal is to retain the meat of the computation and remove the noise. Or to put it differently, there are many ways to write the same function. Good use of exceptions removes the clutter and leaves the things you care about visible. It's a mechanism, not a moral issue or a religion. So there is nothing wrong with throwing HTTPStatus(409) or HTTPStatus(201), even though it returns state to the environment. If that means the code is more maintainable and more likely to be correct, then that is good use of the mechanism. I usually don't do this, but I really need to post a +1 here: +1
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 00:24:41 UTC, Ola Fosheim Grøstad wrote: I don't see the problem. I'm suggesting value semantics, it can be copied. Then you can't catch by super class. This is not going to fly. When you are in the catch, you are not unwinding anymore. You could indeed loose chaining to be able to reuse the memory, that is not what is slow when it come to exception, so it won't make it fast. You can't have chaining with this scheme...? But since you can only have one instance it has to be initialized with value semantics. It's a small constraint. You write that paragraph like there is some logical links between elements in it, but there is none. Not using regular Itanium-style unwinding will make it potentially faster. The only things that is sure here is that it is going to make the non exception path slower. Without specific we can say anything else than that. Using TLS makes it possible to propagate over non-D code or code where the register pressure is high, It won't help with register pressure. Having a pointer to an exception object in a register is equivalent to having a pointer to a TLS memory area in a register. it can be optimized away so you don't need TLS if you don't span over non-D code. Without specifics, it is another instance of the sufficiently smart compiler running gag. Non D functions can cast by setting the TLS memory to an exception value, then do a regular return. The D function that called the non-D function will check TLS memory to see if there is an exception in flight. You don't make things faster by making the calling convention easier. There is chance that this is gonna fly any better than a flat iron.
Re: Why exceptions for error handling is so important
On Wednesday, 14 January 2015 at 00:40:10 UTC, Meta wrote: On Wednesday, 14 January 2015 at 00:38:21 UTC, Walter Bright wrote: On 1/11/2015 2:48 AM, Walter Bright wrote: However, if exceptions are thrown for errors instead, the programmer has to deliberately add code if he wishes to ignore the error. Interesting that this article just appeared: https://blog.golang.org/errors-are-values by Rob Pike on error handling in Go. He concludes with: But remember: Whatever you do, always check your errors! Which sums up why exceptions are better! But checked exceptions are definitely not. http://www.artima.com/intv/handcuffs.html The best sum up of checked exception you'll find.
Re: Why exceptions for error handling is so important
On 1/11/2015 2:48 AM, Walter Bright wrote: However, if exceptions are thrown for errors instead, the programmer has to deliberately add code if he wishes to ignore the error. Interesting that this article just appeared: https://blog.golang.org/errors-are-values by Rob Pike on error handling in Go. He concludes with: But remember: Whatever you do, always check your errors! Which sums up why exceptions are better!
Re: Why exceptions for error handling is so important
On 2015-01-12 19:28, H. S. Teoh via Digitalmars-d wrote: While I agree with the general sentiment, I think the current convention of using a class hierarchy to implement exceptions is suboptimal. The problem with using a class hierarchy is that, like anything put into a hierarchy, some things just don't fit very well in a single-rooted hierarchy. This is especially true in D because there is no multiple inheritance (and for good reason too; multiple inheritance brings with it a whole set of nasty problems). A recent example was what to do with an exception that wraps around OS-level errors. From an implementor's POV, it makes sense to segregate exception types by implementation, that is, ErrnoException for Posix systems and SystemErrorCodeException (or some such) for Windows. However, this is totally useless to the end user: when you're traversing the filesystem, under this scheme you'd have to catch ErrnoException or catch SystemErrorCodeException (with a static-if on OS type, aka utter ugliness), and then ferret out the specific error code(s) you wish to handle, like what to do with an I/O error vs. a permission-denied error. Why should the *user* have to work with low-level implementation details like mapping Posix errno's and their corresponding Windows error codes to the semantic categories of real interest: i.e., access error / hardware failure / network error, etc.? So from the user's POV, the exception hierarchy ought to be semantically driven, rather than implementationally driven. Instead of ErrnoException and SystemErrorCodeException, one ought to have semantic categories like FileNotFoundException, AccessDeniedException, NetworkException, etc.. However, this is burdensome on the implementor, because now a single underlying implementation like ErrnoException now has to be split across multiple unrelated semantic categories (FileNotFoundException must have an errno field on Posix and a systemErrorCode field on Windows, ditto for NetworkException, IOException, etc. -- and you can't factor it out into a base class because the class hierarchy is semantics driven, so ErrnoException doesn't fit anywhere in the hierarchy). Recently Dmitry (IIRC) came up with the rather clever idea of using interfaces instead of a single-rooted hierarchy for marking up semantic categories instead. Instead of trying to decide on whether we should have implementationally-driven OSException with subclasses ErrnoException and SystemErrorCodeException, or semantically-driven FileSystemException with subclasses FileNotFoundException and AccessDeniedException, we can have both: the class hierarchy itself (i.e. without the interfaces) uses base classes for factoring out implementation details, but tag each exception type with semantic categories derived from a distinct interface hierarchy. So we could have something like this: // Implementational hierarchy class Throwable { ... } class Exception : Throwable { ... } class ErrnoException : Exception { int errno; ... } class SystemErrorCodeException : Exception { int systemErrorCode; ... } // Semantic tags interface FilesystemException; interface FileNotFoundException : FilesystemException; interface AccessDeniedException : FilesystemException; .. // Actual implementations static if (Posix) { // Note: you can even have multiple exception types that // inherit from FileNotFoundException, e.g., one thrown // by a manual stat() check, and one from a common // routine that interprets OS error codes. The user // wouldn't need to know the difference. class FileNotFoundExceptionImpl : ErrnoException, FileNotFoundException { ... } ... // other Posix-specific exceptions here } else static if (Windows) { class FileNotFoundExceptionImpl : SystemErrorCodeException, FileNotFoundException { ... } ... // other Windows-specific exceptions here } So now, user code doesn't have to worry about implementation details like whether the exception came from errno or a Windows error code, you can just catch semantic categories like FileNotFoundException instead. Currently, however, this scheme doesn't quite work because the compiler only allows catching classes derived from Throwable, and interfaces can't derive from non-interface base classes. Besides, I'm not sure the druntime exception catching code can deal with interfaces correctly as opposed to just base classes. But this is definitely an area that D could improve on! I prefer a semantically driven hierarchy. I agree with you that the user should not need to care if the exception originated from D code with a
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 23:18:52 UTC, bearophile wrote: Ola Fosheim Grøstad: (Most of std::C++ is optional, templated and inefficient... There is no consistent culture. Though they got some thing right with unique_ptr and new language features recently.) I don't agree. The basic ideas of STL by Alexander Stepanov are very good. Phobos contains related ideas, repackaged in ranges. Ranges are a little more fundamental, ma but in practice they are often good enough and they are often more handy. Rust has chosen a different way so far, but will improve with higher order generics later. Bye, bearophile Lets not forget Alexander Stepanov created STL for Ada originally, and managed to convince the C++ committee to improve templates in a way that could properly support STL. His ideas from generic programming precede C++. -- Paulo
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 13:28:04 UTC, Ola Fosheim Grøstad wrote: On Tuesday, 13 January 2015 at 12:53:15 UTC, Paulo Pinto wrote: As long as it is only used for scripting nothing. But when people remember to use it for writing applications, then it is just plain slow and I don't see PyPy fixing that. But you don't need everything in an application to be fast, so you can tie components together with scripting. Python is essentially built up around having reasonably fast components that are plugged together. But I expect that Python will be displaced with something that can compile efficiently to javascript. One should keep in mind that javascript is plenty fast for UI-bindings. It is the C++ part of browsers (layout engine) that is the slowest part today, IMO. When WebCL becomes available in browsers you probably could do the majority of applications in the browser. That is kinda scary. So the utility of compiled languages is shrinking fast. A language that makes it easy to connect building blocks and also can be used on both a server and in a webclient (compilable to javascript) will probably win in the long run. There is a reason why Go is getting Ruby and Python developers. Sure, Go is useful for web related infrastructure, has static typing, provides decent concurrency and latency and is more lightweight than JVM. Good all round qualities. Sure, but JavaScript enjoys some of the best JIT compilers for dynamic languages, whereas Python has a JIT compiler that still is catching up with the current language version, doesn't support most of the extensions and is ignored by the CPython developers. If PyPy becomes the official implementation, then I will change my mind. Please note I used Python a lot while at CERN, so I do know the eco-system. -- Paulo
Re: Why exceptions for error handling is so important
On Mon, 2015-01-12 at 13:04 -0800, Walter Bright via Digitalmars-d wrote: On 1/12/2015 11:27 AM, Russel Winder via Digitalmars-d wrote: Unless you are writing Python code. Nobody would be in this forum if we preferred Python :-) Why does one have to prefer a language to the exclusion of all others (unless one is the author of a language ;-) I like Python for lots of things, but it is crap for some, hence Java/Groovy/Scala/Kotlin/Ceylon/Clojure for JVM-based work and C++/D/Rust/Go/Chapel for native-based work. PyD needs more support from the D community! -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 10:51:33 UTC, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 13:04 -0800, Walter Bright via Digitalmars-d wrote: On 1/12/2015 11:27 AM, Russel Winder via Digitalmars-d wrote: Unless you are writing Python code. Nobody would be in this forum if we preferred Python :-) Why does one have to prefer a language to the exclusion of all others (unless one is the author of a language ;-) I like Python for lots of things, but it is crap for some, hence Java/Groovy/Scala/Kotlin/Ceylon/Clojure for JVM-based work and C++/D/Rust/Go/Chapel for native-based work. PyD needs more support from the D community! I've just seen that PyD has moved to github[1] and has had a considerable cleanup of documentation. Hooray :) Now if only we had shared library support on OS X then I could actually use it [1] https://github.com/ariovistus/pyd
Re: Why exceptions for error handling is so important
On Mon, 2015-01-12 at 11:32 -0800, Andrei Alexandrescu via Digitalmars-d wrote: On 1/12/15 11:30 AM, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 10:43 -0800, H. S. Teoh via Digitalmars-d wrote: […] And what exactly should operator[] return if a key wasn't found? […] Go has an interesting solution, key lookup in a map return a pair (result, ok), if lookup succeeded then result is the associated value, if ok is false then result is undefined. I quite like this. How can you like undefined? That's a terrible solution again underlining Go's conflation of union and product types. -- Andrei They may be fiddling with type systems, but I was wrong about undefined: if the key is not found then lookup returns the zero value for the value type. Given this is useless to me, I think in terms of it being undefined, which is technically wrong, but good for my code. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Re: Why exceptions for error handling is so important
On Mon, 2015-01-12 at 12:58 -0800, Walter Bright via Digitalmars-d wrote: On 1/12/2015 11:30 AM, Russel Winder via Digitalmars-d wrote: Go has an interesting solution, key lookup in a map return a pair (result, ok), if lookup succeeded then result is the associated value, if ok is false then result is undefined. I quite like this. That's just putting the responsibility of array bounds checking on the caller. Would you want (result, ok) returned every time you indexed an array? I sure wouldn't. An associative array isn't conceptually any different. Why not? There is a fundamentally different approach to error handling depending on whether exceptions are integral cf. Python or anathema cf. Go and most functional programming languages. It is unreasonable to impose the idioms of one model onto another. And vice versa. arrays, sparse arrays and associative arrays are both very different and quite similar. The properties of the keys makes for very different approaches to algorithms, and possibly error handling of key lookup: contiguity of keys of an array is important. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Re: Why exceptions for error handling is so important
On Tue, 2015-01-13 at 06:50 +, Tobias Müller via Digitalmars-d wrote: […] The problem with exceptions is, that the *callee* has to decide, not the caller. Callee always has the responsibility, it is just a question of whether or how callee may propagate the problem back up the chain. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Re: Why exceptions for error handling is so important
On Mon, 2015-01-12 at 12:52 -0800, Walter Bright via Digitalmars-d wrote: […] If code is throwing exceptions as part of its normal operation, it is designed wrong. OK so I know you hate Python, but… And yes, if you take that as a challenge to try and concoct a counterexample, the point still stands :-) Python. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Re: Why exceptions for error handling is so important
On Tue, 2015-01-13 at 10:58 +, John Colvin via Digitalmars-d wrote: […] I've just seen that PyD has moved to github[1] and has had a considerable cleanup of documentation. Hooray :) Now if only we had shared library support on OS X then I could actually use it The standard Go development team response to the we must have dynamic library support in Go is you do not need it, use operating system processes and pipes. For operating systems that support many small processes, this is a most viable solution. UNIX and Linux are supposed to be such. Of course it helps that Go is channel and dataflow focused, so it is just a variation of the standard model. Conversely CPython (and now by necessity PyPy, but not Jython or IronPython since it is irrelevant for them) trivially supports C and C++ for extensions. If D is to compete in this milieu, it is essentially to support C linkage dynamic linking on all platforms. I'm on Linux, it works for me :-) On the other hand if it doesn't work on Windows and OSX then perhaps it is broken? [1] https://github.com/ariovistus/pyd -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Re: Why exceptions for error handling is so important
Ola Fosheim Grøstad: I've tried to like STL for 17 years, and whenever speed and clear programming matters it is basically a good idea to throw it out. Take a look at the ideas of C++ seasoning (http://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning ), where they suggest to do kind of the opposite of what you do, it means throwing out loops and other things, and replacing them with standard algorithms. A solution like list comprehensions is a lot easier on the programmer, if convenience is the goal. There's still time to add lazy and eager sequence comprehensions (or even better the computational thinghies of F#) to D, but past suggestions were not welcomed. D has lot of features, adding more and more has costs. Phobos ranges need a next_simd() to be efficient. Right? Perhaps, but first std.simd needs to be finished. Bye, bearophile
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 09:58:56 UTC, bearophile wrote: Take a look at the ideas of C++ seasoning (http://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning ), where they suggest to do kind of the opposite of what you do, it means throwing out loops and other things, and replacing them with standard algorithms. Yes... you can do that. For little gain since C++'s support for high level programming is bloat inducing. Just take a look of all the symbols you need to have a conforming iterator or allocator... An allocator should be a simple 5 line snippet, it is bloatsome in STL: https://gist.github.com/donny-dont/1471329 Then I needed a circular buffer. STL didn't have one. So I downloaded the Boost one. It was terribly inefficient, because it was generic and STLish. I ended up writing my own using a fixed size log2 array with a start and end index. Clean conditional-free efficient code due to the log2 property and modular arithmetics. So, in the end I get something faster, that produce more readable code, give faster compiles, is easier to read, is easier to debug and was implemented in less time than finding and figuring out the Boost one... I have no problem with using arrayT and vectorT where it fits, but in the end templated libraries prevent transparency. If you want speed you need to understand layout. Concrete implementations make that easier. A solution like list comprehensions is a lot easier on the programmer, if convenience is the goal. There's still time to add lazy and eager sequence comprehensions (or even better the computational thinghies of F#) to D, but past suggestions were not welcomed. D has lot of features, adding more and more has costs. Phobos ranges need a next_simd() to be efficient. Right? Perhaps, but first std.simd needs to be finished. Right, but you need to support masked simd if you want to do filtering. Maybe autovectorization is the only path. Still, you also need to keep your loops tiny if you want to benefit from X86 loop buffer. The CPU is capable of unrolling tight loops in hardware before hitting the execution pipeline. Thus getting the conditionals out of the pipeline. Then you have cache locality. You need to break up long loops so you don't push things out of the caches. So, if you can gain 2x by good cache locality/prefetching and 4x by using AVX over scalars, then you gain 8x performance over a naive implementation. That hurts.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 19:27:34 UTC, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 09:54 -0800, H. S. Teoh via Digitalmars-d wrote: […] Yeah, exceptions are supposed to be ... well, *exceptions*, rather than the norm. :-) If you're using exceptions to do flow control, you're doing something wrong. […] Unless you are writing Python code. You are doing Python a disservice here. Their use of exceptions for control flow statements is an implementation detail, introduced because Python exceptions are fast. (In the C runtime a Python exception is a global variable and functions that return 0;. ) The whole argument stands on its head. The discussion of good Python coding style and Python's usefulness might be found elsewhere.
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 12:53:15 UTC, Paulo Pinto wrote: As long as it is only used for scripting nothing. But when people remember to use it for writing applications, then it is just plain slow and I don't see PyPy fixing that. But you don't need everything in an application to be fast, so you can tie components together with scripting. Python is essentially built up around having reasonably fast components that are plugged together. But I expect that Python will be displaced with something that can compile efficiently to javascript. One should keep in mind that javascript is plenty fast for UI-bindings. It is the C++ part of browsers (layout engine) that is the slowest part today, IMO. When WebCL becomes available in browsers you probably could do the majority of applications in the browser. That is kinda scary. So the utility of compiled languages is shrinking fast. A language that makes it easy to connect building blocks and also can be used on both a server and in a webclient (compilable to javascript) will probably win in the long run. There is a reason why Go is getting Ruby and Python developers. Sure, Go is useful for web related infrastructure, has static typing, provides decent concurrency and latency and is more lightweight than JVM. Good all round qualities.
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 11:23:27 UTC, Russel Winder via Digitalmars-d wrote: On Tue, 2015-01-13 at 10:58 +, John Colvin via Digitalmars-d wrote: […] I've just seen that PyD has moved to github[1] and has had a considerable cleanup of documentation. Hooray :) Now if only we had shared library support on OS X then I could actually use it The standard Go development team response to the we must have dynamic library support in Go is you do not need it, use operating system processes and pipes. For operating systems that support many small processes, this is a most viable solution. UNIX and Linux are supposed to be such. Of course it helps that Go is channel and dataflow focused, so it is just a variation of the standard model. Which doesn't scale in software that requires plugins. Imagine Eclipse, for example, implemented as a collection of processes. -- Paulo
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 19:32:22 UTC, Andrei Alexandrescu wrote: On 1/12/15 11:30 AM, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 10:43 -0800, H. S. Teoh via Digitalmars-d wrote: […] And what exactly should operator[] return if a key wasn't found? […] Go has an interesting solution, key lookup in a map return a pair (result, ok), if lookup succeeded then result is the associated value, if ok is false then result is undefined. I quite like this. How can you like undefined? That's a terrible solution again underlining Go's conflation of union and product types. -- Andrei They posted recently a blog post about error handling in Go. https://blog.golang.org/errors-are-values -- Paulo
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 10:51:33 UTC, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 13:04 -0800, Walter Bright via Digitalmars-d wrote: On 1/12/2015 11:27 AM, Russel Winder via Digitalmars-d wrote: Unless you are writing Python code. Nobody would be in this forum if we preferred Python :-) Why does one have to prefer a language to the exclusion of all others (unless one is the author of a language ;-) I have found that Python quite nicely can replace perl, php, bash, awk and sed... What's not to like about this swiss army knife that can get rid of all that junk? I like Python for lots of things, but it is crap for some, hence Java/Groovy/Scala/Kotlin/Ceylon/Clojure for JVM-based work and I have almost no experience with these, why so many? What do they bring to the table versus one another? PyD needs more support from the D community! I'd consider using Python with D if the memory model was integrated. Not a bad idea, actually, but would take some real work.
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 12:14:07 UTC, Ola Fosheim Grøstad wrote: On Tuesday, 13 January 2015 at 10:51:33 UTC, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 13:04 -0800, Walter Bright via Digitalmars-d wrote: On 1/12/2015 11:27 AM, Russel Winder via Digitalmars-d wrote: Unless you are writing Python code. Nobody would be in this forum if we preferred Python :-) Why does one have to prefer a language to the exclusion of all others (unless one is the author of a language ;-) I have found that Python quite nicely can replace perl, php, bash, awk and sed... What's not to like about this swiss army knife that can get rid of all that junk? As long as it is only used for scripting nothing. But when people remember to use it for writing applications, then it is just plain slow and I don't see PyPy fixing that. There is a reason why Go is getting Ruby and Python developers. -- Paulo
Re: Why exceptions for error handling is so important
On Tue, 2015-01-13 at 11:50 +, Paulo Pinto via Digitalmars-d wrote: […] Which doesn't scale in software that requires plugins. Probably true. Imagine Eclipse, for example, implemented as a collection of processes. Imagine Eclipse actually working… ;-) -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Why exceptions for error handling is so important
On Tue, 2015-01-13 at 13:29 +, via Digitalmars-d wrote: […] You are doing Python a disservice here. Their use of exceptions for control flow statements is an implementation detail, introduced because Python exceptions are fast. (In the C runtime a Python exception is a global variable and functions that return 0;. ) The whole argument stands on its head. I think you miss my point. The thread appeared to be assuming the use of exception handling was a boolean, whereas it is a scale. The cost of raising and handling an exception compared to the cost of a function call is a critical metric. Thus C++ exception handling is at one scale, Python at a totally different one, with Java somewhere between. The cost determines the idioms. Because exceptions are so cheap in Python it can be used for implementation detail, and is. I assume D sits with C++ rather than Java, so exception handling is for termination semantics, not error handling. Certainly not for control flow as with Python. Go does have exceptions, there is one and it terminates execution. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Why exceptions for error handling is so important
Of course the best solution might be to just implement reasonably fast exceptions by: 1. Restricting the exception object to 512 bytes, preallocated in TLS. 2. Only have one exception in flight per thread 3. Require that the first 8 bytes of the exception buffer are 0 when no exception is in flight, and use them for encoding exception type when one is in flight. 4. Leave it to the implementation how to propagate awareness of an exception. (LLVM has many different calling conventions, it might be desirable to do it different for each one). 5. Constrain calls from C to D to nothrow functions.
Re: Why exceptions for error handling is so important
On 1/13/2015 11:42 AM, Marc =?UTF-8?B?U2Now7x0eiI=?= schue...@gmx.net wrote: On Tuesday, 13 January 2015 at 00:05:31 UTC, Walter Bright wrote: On 1/12/2015 3:17 PM, deadalnix wrote: On Monday, 12 January 2015 at 22:17:57 UTC, Walter Bright wrote: Yes, it does. Returning an int in EAX now becomes returning a pair [EAX,EDX]. It is not that big of a deal, EDX is a trash register anyway if memory serve, but then, it become very bad when it do not fit in register anymore. Returning a slice, for example, already consumes EAX and EDX. Adding an error code pushes that into returning via a pointer to a stack temporary. There are techniques to mitigate that. For example, Rust is smart enough to encode the not-present state for pointers as a NULL pointer (Rust pointers are non-null). Such mitigation techniques pretty much confirms there's an efficiency cost to having the error code. If an error code needs to be returned, it can be encoded as a misaligned pointer (if you're feeling adventurous). Don't know whether Rust does the latter, though. Of course, these things have costs of their own.
Re: Why exceptions for error handling is so important
On 1/13/2015 3:01 AM, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 12:58 -0800, Walter Bright via Digitalmars-d wrote: On 1/12/2015 11:30 AM, Russel Winder via Digitalmars-d wrote: Go has an interesting solution, key lookup in a map return a pair (result, ok), if lookup succeeded then result is the associated value, if ok is false then result is undefined. I quite like this. That's just putting the responsibility of array bounds checking on the caller. Would you want (result, ok) returned every time you indexed an array? I sure wouldn't. An associative array isn't conceptually any different. Why not? There is a fundamentally different approach to error handling depending on whether exceptions are integral cf. Python or anathema cf. Go and most functional programming languages. It is unreasonable to impose the idioms of one model onto another. And vice versa. My point was more to the issue of how is array bounds checking done in those languages, and that aa checking should behave the same way when doing the same operations. arrays, sparse arrays and associative arrays are both very different and quite similar. The properties of the keys makes for very different approaches to algorithms, and possibly error handling of key lookup: contiguity of keys of an array is important. In trying to make component programming work, I look for emphasizing similarities between containers rather than differences, in this case, what happens when presenting an invalid index. Similarity in basic operations like that make it easy to swap in and out different containers without having to redo the rest of the code's interface to it.
Re: Why exceptions for error handling is so important
13-Jan-2015 02:01, Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= ola.fosheim.grostad+dl...@gmail.com пишет: On Monday, 12 January 2015 at 22:06:32 UTC, deadalnix wrote: If you put aside performance concerns, exceptions for control flow also tend to make many code path implicit and makes for very unreadable/unmaintainable code. But exceptions are control flow. There is no such thing as normalized control flow, all state changes implies control flow. Think in terms of a state machine. You could just remove all variables and only have a big state machine (assuming finite dimensions). Every single state transition implies flow of control. The control flow you see in the source code is just the programmer's rendition of control flow. Exceptions is a mechanism for getting cluttering resolution out of that rendition to make the code more readable and maintainable. The goal is to retain the meat of the computation and remove the noise. Or to put it differently, there are many ways to write the same function. Good use of exceptions removes the clutter and leaves the things you care about visible. It's a mechanism, not a moral issue or a religion. So there is nothing wrong with throwing HTTPStatus(409) or HTTPStatus(201), even though it returns state to the environment. If that means the code is more maintainable and more likely to be correct, then that is good use of the mechanism. Actually I agree - exceptions are mechanism. Stressing _exceptional_ as in happening very rarely is just a poor excuse to never optimize this control-flow mechanism. I guess C/C++ inspired languages would never have fast exceptions simply because of the mindset with the perception of them being non-important or rare. Big adopters of C++ often avoided exceptions entirely to not pollute binaries with EH-code only making this issue worse. In contrast, Java optimizes exceptions and re-writes many try/catch to plain gotos on error control flows. -- Dmitry Olshansky
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 19:36:31 UTC, Marc Schütz wrote: On Monday, 12 January 2015 at 23:01:53 UTC, Ola Fosheim Grøstad wrote: On Monday, 12 January 2015 at 22:06:32 UTC, deadalnix wrote: No, Exception are a bail out mechanism. It is the, I have no idea what to do about this mechanism. The way it is done in C++, yes. If you put aside performance concerns, exceptions for control flow also tend to make many code path implicit and makes for very unreadable/unmaintainable code. But exceptions are control flow. There is no such thing as normalized control flow, all state changes implies control flow. Think in terms of a state machine. You could just remove all variables and only have a big state machine (assuming finite dimensions). Every single state transition implies flow of control. The control flow you see in the source code is just the programmer's rendition of control flow. Exceptions is a mechanism for getting cluttering resolution out of that rendition to make the code more readable and maintainable. The goal is to retain the meat of the computation and remove the noise. Or to put it differently, there are many ways to write the same function. Good use of exceptions removes the clutter and leaves the things you care about visible. It's a mechanism, not a moral issue or a religion. So there is nothing wrong with throwing HTTPStatus(409) or HTTPStatus(201), even though it returns state to the environment. If that means the code is more maintainable and more likely to be correct, then that is good use of the mechanism. I usually don't do this, but I really need to post a +1 here: +1 Too bad you chose to do this on a bad strawmman.
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 03:05:57 UTC, Walter Bright wrote: On 1/12/2015 4:40 PM, deadalnix wrote: These are trash register. Meaning the callee can put whatever in them. The caller must consider them trashed after the call. So no, it do NOT increase register pressure. 1. the register must be assigned a value - that has a cost xor on Haswell has a reciprocal throughput of 0.25, meaning execution of 4 instructions per cycle per core. 3. it prevents EDX from being used by the return value, when the return value is larger than a single register size Store the error in TLS memory using a write-through (no load from memory) instruction and use the carry-flag instead then (assuming the return instruction does not clear carry). CLC has reciprocal throughput of 0.25 too. 4. static functions may not need to follow the C ABI register convention, and can be so optimized D calls D, no problem. D calls C, no problem, C can't return D errors... C calls D, a problem no matter what solution you pick.
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 22:46:26 UTC, Ola Fosheim Grøstad wrote: Of course the best solution might be to just implement reasonably fast exceptions by: 1. Restricting the exception object to 512 bytes, preallocated in TLS. Exception can bubble from one thread to another. 2. Only have one exception in flight per thread I don't see how you could have more. 3. Require that the first 8 bytes of the exception buffer are 0 when no exception is in flight, and use them for encoding exception type when one is in flight. The first 8 bytes are already what is used to do matching. But, because of inheritance, it is not as simple as you think it is. Also, who the fuck care what is in the buffer when no exception are in flight ? Skipping 4 and 5, you obviously didn't though that through.
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 23:40:41 UTC, deadalnix wrote: 1. Restricting the exception object to 512 bytes, preallocated in TLS. Exception can bubble from one thread to another. How? If you are thinking coroutines, then the exception can be moved with it. 2. Only have one exception in flight per thread I don't see how you could have more. In a catch you can throw a new one and initialize with the old, but if they are both in the same memory space it will go wrong. 3. Require that the first 8 bytes of the exception buffer are 0 when no exception is in flight, and use them for encoding exception type when one is in flight. The first 8 bytes are already what is used to do matching. But, because of inheritance, it is not as simple as you think it is. Also, who the fuck care what is in the buffer when no exception are in flight ? 1. So that you can mark a non-D function with @checkexception and allow it to both cast D-exceptions and propagate D-exceptions. Skipping 4 and 5, you obviously didn't though that through. ?
Re: Why exceptions for error handling is so important
On Tuesday, 13 January 2015 at 23:47:58 UTC, Ola Fosheim Grøstad wrote: On Tuesday, 13 January 2015 at 23:40:41 UTC, deadalnix wrote: 1. Restricting the exception object to 512 bytes, preallocated in TLS. Exception can bubble from one thread to another. How? If you are thinking coroutines, then the exception can be moved with it. http://dlang.org/phobos/core_thread.html#.Thread.join 2. Only have one exception in flight per thread I don't see how you could have more. In a catch you can throw a new one and initialize with the old, but if they are both in the same memory space it will go wrong. When you are in the catch, you are not unwinding anymore. You could indeed loose chaining to be able to reuse the memory, that is not what is slow when it come to exception, so it won't make it fast. 3. Require that the first 8 bytes of the exception buffer are 0 when no exception is in flight, and use them for encoding exception type when one is in flight. The first 8 bytes are already what is used to do matching. But, because of inheritance, it is not as simple as you think it is. Also, who the fuck care what is in the buffer when no exception are in flight ? 1. So that you can mark a non-D function with @checkexception and allow it to both cast D-exceptions and propagate D-exceptions. Empty hand waving, not not addressing the point. Skipping 4 and 5, you obviously didn't though that through. ? What you propose in point 1 - 3 is weak at best. You haven't put serious effort thinking about what you are proposing, so there is no reason anyone should spend any serious effort criticizing it.
Re: Why exceptions for error handling is so important
Walter Bright: I do understand that the packed error code technique can be made to work, but the inconvenience seems to be high. Apparently if the language syntax is designed for that style of functional programming, the inconvenience seems to be very low. Bye, bearophile
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 09:41:08 UTC, bearophile wrote: Walter Bright: I do understand that the packed error code technique can be made to work, but the inconvenience seems to be high. Apparently if the language syntax is designed for that style of functional programming, the inconvenience seems to be very low. Yes, dataflow.
Re: Why exceptions for error handling is so important
On 1/11/2015 11:53 PM, Tobias Pankrath wrote: On Monday, 12 January 2015 at 00:51:25 UTC, Walter Bright wrote: This matters very much for pipeline style programming (i.e. ranges and algorithms). Here is one approach to it: http://fsharpforfunandprofit.com/posts/recipe-part2/ I don't fully understand it, but it appears to require that each component have two paths coded into it - the regular path, and the error path, and there has to be adapters for components that only have a regular path. Exceptions means only one path has to be coded. I do understand that the packed error code technique can be made to work, but the inconvenience seems to be high.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 09:31:25 UTC, Walter Bright wrote: On 1/11/2015 11:53 PM, Tobias Pankrath wrote: On Monday, 12 January 2015 at 00:51:25 UTC, Walter Bright wrote: This matters very much for pipeline style programming (i.e. ranges and algorithms). Here is one approach to it: http://fsharpforfunandprofit.com/posts/recipe-part2/ I don't fully understand it, but it appears to require that each component have two paths coded into it - the regular path, and the error path, and there has to be adapters for components that only have a regular path. Exceptions means only one path has to be coded. I do understand that the packed error code technique can be made to work, but the inconvenience seems to be high. Not really, after you have the library that can handle all code paths, the code just needs to be written using such building blocks[0], as they are quite general. Which is relatively easy in FP first languages. [0] Aka monadic combinators
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 11:43:26 UTC, Ola Fosheim Grøstad wrote: Does this mean that D will get fast EH? It is fast already...
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 13:25:26 UTC, Adam D. Ruppe wrote: On Monday, 12 January 2015 at 11:43:26 UTC, Ola Fosheim Grøstad wrote: Does this mean that D will get fast EH? It is fast already... What makes you say that? Doesn't D still use the standard zero-cost EH that was created for Itanium, where you take the performance hit on unwinding?
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 00:51:25 UTC, Walter Bright wrote: On 1/11/2015 5:06 AM, Dicebot wrote: What is your opinion of approach advertised by various functional languages and now also Rust? Where you return error code packed with actual data and can't access data without visiting error code too, compiler simply won't allow it. It's a great question. I have a lot of experience with error codes, and with exceptions. I have zero with the packed scheme, though that doesn't stop me from having an opinion :-) Perhaps I misunderstand, but given A calls B calls C, A = B = C The general solution in functional programming is error chaining. An example, C is a function that reads in lines of a program and B is a function that takes all those lines and counts words. C will either return an error or lines and B will either immediately return that error to A or convert the lines to word counts. This works especially well with function chaining, because you can hide the error propagation in a generic chaining method (called map). http://danielwestheide.com/blog/2012/12/26/the-neophytes-guide-to-scala-part-6-error-handling-with-try.html
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 11:09:01 UTC, Walter Bright wrote: On 1/12/2015 3:02 AM, Tobias Pankrath wrote: As far as I understand is, it requires each component to settle on the same discriminated union that packs the error and result, which he calles Result but is usually Choice in F#. Now in D we use the opDot to chain components, which works since we have UFCS. In F# there a simply three different opDots: , = and = which take care of the adaption. Or we could just use exceptions, which require none of that. Interesting little rant about exceptions (and more), from the author of a large and successful project in C++ http://250bpm.com/blog:4
Re: Why exceptions for error handling is so important
On 11 January 2015 at 10:48, Walter Bright via Digitalmars-d digitalmars-d@puremagic.com wrote: Over the last few days, I have been getting weird errors from various programs I run on Windows 7. Programs would just fail, or produce corrupt output (I'm looking at you, Windows Moviemaker). I have a 128Gb SSD drive for my system drive, for speed, and a 4T secondary spinning drive for storage. I knew I was getting nearly out of space on the SSD drive, and had a 256Gb SSD drive ready to swap in. To migrate the system to the new disk, the idea was to use Windows Backup/Restore of the image. Unfortunately, Windows Backup would get a ways through the process, then fail with no message beyond an error code. Googling the error code produced a vast number of results, and various schemes for fixing it, some official, some not. None of them were applicable. Many involved loading new drivers, editting the system registry, and all sort of unappealing solutions. Up to this point, I you reminded me of a talk by Joe Armstrong (inventor of Erlang) https://www.youtube.com/watch?v=lKXe3HUG2l4
Re: Why exceptions for error handling is so important
On 1/12/2015 3:28 AM, Andrej Mitrovic via Digitalmars-d wrote: If you haven't read this I highly recommend it, just for the entertainment value: http://blog.seattlepi.com/microsoft/2008/06/24/full-text-an-epic-bill-gates-e-mail-rant/ Epic! But we all have such issues. And it ain't just software, either, every machine that has a user interface, like cars and airplanes and dishwashers, have these usability issues that are so obviously wrong yet nobody thought of them.
Re: Why exceptions for error handling is so important
On 1/12/2015 3:02 AM, Tobias Pankrath wrote: As far as I understand is, it requires each component to settle on the same discriminated union that packs the error and result, which he calles Result but is usually Choice in F#. Now in D we use the opDot to chain components, which works since we have UFCS. In F# there a simply three different opDots: , = and = which take care of the adaption. Or we could just use exceptions, which require none of that.
Re: Why exceptions for error handling is so important
On 1/12/2015 2:04 AM, Iain Buclaw via Digitalmars-d wrote: Up to this point, I you reminded me of a talk by Joe Armstrong (inventor of Erlang) https://www.youtube.com/watch?v=lKXe3HUG2l4 I've found another problem with Windows Moviemaker, it can read, but cannot write, movies larger than 4Gb. Looks like some sort of internal 32 bit overflow. I am once again a unique snowflake, because in googling around I can find nobody else with this issue. (I have many 6Gb video files, as they come from my old 6 hour VHS tapes made in the 80's. I decided to digitize them and throw the tapes away. VHS tapes are only supposed to last 10 years, I am frankly amazed that they are in good shape after 30. My video capture device generates about 1Gb per hour of video.)
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 11:09:01 UTC, Walter Bright wrote: On 1/12/2015 3:02 AM, Tobias Pankrath wrote: As far as I understand is, it requires each component to settle on the same discriminated union that packs the error and result, which he calles Result but is usually Choice in F#. Now in D we use the opDot to chain components, which works since we have UFCS. In F# there a simply three different opDots: , = and = which take care of the adaption. Or we could just use exceptions, which require none of that. .. and have many other issues instead :) Right now my experience from some quick experiments with Rust seems to indicate that it is a good sort inconvenience for medium-to-big applications as it forces you to explicitly consider all possible exceptional paths possible in application without and does not add any runtime overhead. For smaller / less important programs verbosity does seem inconvenient in an unpleasant way indeed.
Re: Why exceptions for error handling is so important
On 1/12/15, Walter Bright via Digitalmars-d digitalmars-d@puremagic.com wrote: I've found another problem with Windows Moviemaker, it can read, but cannot write, movies larger than 4Gb. Looks like some sort of internal 32 bit overflow. If you haven't read this I highly recommend it, just for the entertainment value: http://blog.seattlepi.com/microsoft/2008/06/24/full-text-an-epic-bill-gates-e-mail-rant/
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 09:31:25 UTC, Walter Bright wrote: On 1/11/2015 11:53 PM, Tobias Pankrath wrote: On Monday, 12 January 2015 at 00:51:25 UTC, Walter Bright wrote: This matters very much for pipeline style programming (i.e. ranges and algorithms). Here is one approach to it: http://fsharpforfunandprofit.com/posts/recipe-part2/ I don't fully understand it, but it appears to require that each component have two paths coded into it - the regular path, and the error path, and there has to be adapters for components that only have a regular path. Exceptions means only one path has to be coded. As far as I understand is, it requires each component to settle on the same discriminated union that packs the error and result, which he calles Result but is usually Choice in F#. Now in D we use the opDot to chain components, which works since we have UFCS. In F# there a simply three different opDots: , = and = which take care of the adaption.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 11:09:01 UTC, Walter Bright wrote: On 1/12/2015 3:02 AM, Tobias Pankrath wrote: As far as I understand is, it requires each component to settle on the same discriminated union that packs the error and result, which he calles Result but is usually Choice in F#. Now in D we use the opDot to chain components, which works since we have UFCS. In F# there a simply three different opDots: , = and = which take care of the adaption. Or we could just use exceptions, which require none of that. Well, yes. I don't think though, that either exception or railway requires more boilerplate than the other. They just offer different strength. The plus side for railway (as compared D exceptions): Easier comprehension of control flow and scope(exit) and scope(failure) are not needed anymore. Using something like this in @nogc functions seems easier than making exceptions work by preallocating them. Haven't programmed anything of value in F# though.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 11:41:06 UTC, Walter Bright wrote: For me the primary advantage of EH is put the code to deal with the error in the place where it is most appropriate to deal with it. With error codes, you have to deal with propagating Does this mean that D will get fast EH?
Re: Why exceptions for error handling is so important
On 1/12/2015 3:27 AM, Dicebot wrote: .. and have many other issues instead :) Right now my experience from some quick experiments with Rust seems to indicate that it is a good sort inconvenience for medium-to-big applications as it forces you to explicitly consider all possible exceptional paths possible in application without and does not add any runtime overhead. For smaller / less important programs verbosity does seem inconvenient in an unpleasant way indeed. For me the primary advantage of EH is put the code to deal with the error in the place where it is most appropriate to deal with it. With error codes, you have to deal with propagating the errors everywhere. Error codes still require manual insertion of unwinding code, and that can get fairly ugly when dealing with transactions: http://dlang.org/exception-safe.html Scope guard and RAII deal with most of the issues with having correct error recovery.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 13:54:18 UTC, Ola Fosheim Grøstad wrote: On Monday, 12 January 2015 at 13:25:26 UTC, Adam D. Ruppe wrote: On Monday, 12 January 2015 at 11:43:26 UTC, Ola Fosheim Grøstad wrote: Does this mean that D will get fast EH? It is fast already... What makes you say that? Doesn't D still use the standard zero-cost EH that was created for Itanium, where you take the performance hit on unwinding? The advantage of return code / union type error handling is that the exceptional case is as fast as the successful case. The disadvantage of return code / union type error handling is that the successful case is as slow as the exceptional case. So which method is faster depends on how exceptional your exceptions are.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 16:15:34 UTC, Matthias Bentrup wrote: The disadvantage of return code / union type error handling is that the successful case is as slow as the exceptional case. It is in a register...
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 18:45:22 UTC, H. S. Teoh via Digitalmars-d wrote: The only sane way is to have the user specify a default value if the key wasn't found, since not all types have a null value (and besides, what if null is a valid value in the dictionary?). IOW something like TryGetValue that takes multiple arguments instead of operator[]. Yes, and then think about the original foundation for exceptions. An exception is mean to resolve situations where you call from a higher level layer into a lower level layer (or framework). The basic idea is that the higher level layer has information that the lower layer does not. So if you have exceptions with retry you get this: 1. High Level calls into low level 2. Low Level goes Lord High Level, I am your humble servant, but cannot compute 3/0. What shall I do? 3. High Level ponders for a while and says replace it with infinity and continue 4. Low Level comes back and say Lord High Level, I cannot find 'flowers.png'. 5. High Level responds Use 'default.png' instead. 6. Low Level comes back crying I can't find that either. 7. High Level gives up and says roll back, backtrack... Exceptions are basically about deferring decision making from an encapsulated context to the calling context. Without retries, you just have a backtracking mechanism. Don't get hung upon the terminology. Use it for writing maintainable code! You really should be using operator[] only when the key is expected to exist. If during normal operations there's a 50% chance the key doesn't already exist, you shouldn't be using []. This is getting very normative. Where did you get that 50% from? If you had exceptions with retry you could just look it up in a default directory for instance, or even made a call to another process to get a substitute value. Besides, if you are doing validation then it is desirable to get an exception for an illegal key. Don't let a crappy implementation of exception handling define general semantics. Improve the implementation instead.
Re: Why exceptions for error handling is so important
On Mon, 12 Jan 2015 18:11:01 + via Digitalmars-d digitalmars-d@puremagic.com wrote: returning state with exceptions (banging his head against a wall) NO. THIS NEVER HAS ANY SENSE. signature.asc Description: PGP signature
Re: Why exceptions for error handling is so important
On 1/12/15 11:30 AM, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 10:43 -0800, H. S. Teoh via Digitalmars-d wrote: […] And what exactly should operator[] return if a key wasn't found? […] Go has an interesting solution, key lookup in a map return a pair (result, ok), if lookup succeeded then result is the associated value, if ok is false then result is undefined. I quite like this. How can you like undefined? That's a terrible solution again underlining Go's conflation of union and product types. -- Andrei
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 19:30:10 UTC, Russel Winder via Digitalmars-d wrote: On Mon, 2015-01-12 at 10:43 -0800, H. S. Teoh via Digitalmars-d wrote: […] And what exactly should operator[] return if a key wasn't found? […] Go has an interesting solution, key lookup in a map return a pair (result, ok), if lookup succeeded then result is the associated value, if ok is false then result is undefined. I quite like this. That's basically the same as a pointer to the value. If the pointer is null, dereferencing it is undefined.
Re: Why exceptions for error handling is so important
On Sunday, 11 January 2015 at 13:06:27 UTC, Dicebot wrote: What is your opinion of approach advertised by various functional languages and now also Rust? Where you return error code packed with actual data and can't access data without visiting error code too, compiler simply won't allow it. Rust has an approach very similar to exception, but they do not unwind and trash the whole task instead. Under the hood, it is exception, but tend to be faster as you don't go through the landing pad/personality function dance, but do not fundamentally differ. The second approach is to pack the result in some kind of object that require checking (but you often don't have anything meaningful to do on failure where you need to check) or propagate the wrapper, à la maybe monad, and get rid of the wrapper where you know what to do on error. These approach tend to be faster while keeping safety, but requiring more work from the dev. They make sense if the error is common, but are not pulling their weight for very rare failure scenarios like disc running out of space.
Re: Why exceptions for error handling is so important
On Mon, 2015-01-12 at 09:54 -0800, H. S. Teoh via Digitalmars-d wrote: […] Yeah, exceptions are supposed to be ... well, *exceptions*, rather than the norm. :-) If you're using exceptions to do flow control, you're doing something wrong. […] Unless you are writing Python code. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Re: Why exceptions for error handling is so important
On Mon, 2015-01-12 at 10:43 -0800, H. S. Teoh via Digitalmars-d wrote: […] And what exactly should operator[] return if a key wasn't found? […] Go has an interesting solution, key lookup in a map return a pair (result, ok), if lookup succeeded then result is the associated value, if ok is false then result is undefined. I quite like this. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 19:24:35 UTC, ketmar via Digitalmars-d wrote: On Mon, 12 Jan 2015 18:11:01 + via Digitalmars-d digitalmars-d@puremagic.com wrote: returning state with exceptions (banging his head against a wall) NO. THIS NEVER HAS ANY SENSE. Sure it has. It is a state machine. You cannot not return state. :-P
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 20:07:17 UTC, deadalnix wrote: On Sunday, 11 January 2015 at 13:06:27 UTC, Dicebot wrote: What is your opinion of approach advertised by various functional languages and now also Rust? Where you return error code packed with actual data and can't access data without visiting error code too, compiler simply won't allow it. Rust has an approach very similar to exception, but they do not unwind and trash the whole task instead. Under the hood, it is exception, but tend to be faster as you don't go through the landing pad/personality function dance, but do not fundamentally differ. The second approach is to pack the result in some kind of object that require checking (but you often don't have anything meaningful to do on failure where you need to check) or propagate the wrapper, à la maybe monad, and get rid of the wrapper where you know what to do on error. These approach tend to be faster while keeping safety, but requiring more work from the dev. They make sense if the error is common, but are not pulling their weight for very rare failure scenarios like disc running out of space. Exceptions in Rust are more like Errors in D (but they terminate tasks, not the process!), Result wrapper seems to be standard approach for tasks D uses exceptions for, thus my original question.
Re: Why exceptions for error handling is so important
On 1/12/2015 10:11 AM, Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= ola.fosheim.grostad+dl...@gmail.com wrote: There are plenty of situations where exceptions used for retries is the most sensible solution. Heck, that's even how x86 floating point exceptions work. There are plenty of situations where returning state with exceptions makes the most sense, e.g. a web service request handler. I've never encountered any IEEE FP code that ever, and I mean ever, checked the 'exception' sticky flag that IEEE operations require. Outside of a FP test suite, that is. Nobody has ever turned on the FP hardware exception faults, either. Bringing up IEEE 754 FP exceptions as an example of it being done right when it is a complete failure severely damages your case.
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 20:07:17 UTC, deadalnix wrote: On Sunday, 11 January 2015 at 13:06:27 UTC, Dicebot wrote: What is your opinion of approach advertised by various functional languages and now also Rust? Where you return error code packed with actual data and can't access data without visiting error code too, compiler simply won't allow it. Rust has an approach very similar to exception, but they do not unwind and trash the whole task instead. Under the hood, it is exception, but tend to be faster as you don't go through the landing pad/personality function dance, but do not fundamentally differ. It is difficult to introduce exceptions without causing problems for linear typing. http://www.serc.iisc.ernet.in/~govind/NHC-07/final/ExceptionsSlides.pdf
Re: Why exceptions for error handling is so important
On Monday, 12 January 2015 at 13:33:40 UTC, John Colvin wrote: On Monday, 12 January 2015 at 11:09:01 UTC, Walter Bright wrote: On 1/12/2015 3:02 AM, Tobias Pankrath wrote: As far as I understand is, it requires each component to settle on the same discriminated union that packs the error and result, which he calles Result but is usually Choice in F#. Now in D we use the opDot to chain components, which works since we have UFCS. In F# there a simply three different opDots: , = and = which take care of the adaption. Or we could just use exceptions, which require none of that. Interesting little rant about exceptions (and more), from the author of a large and successful project in C++ http://250bpm.com/blog:4 Exception in C++ is different. It is full of pitfalls and generally a usability disaster. I can understand that C++ dev do not like exception, but that say more about C++ than it does about exceptions.