digitalmars.D - Checked vs unchecked exceptions
- mckoder (54/54) Jun 25 2017 I am disappointed that D doesn't have checked exceptions.
- Eugene Wissner (2/57) Jun 25 2017
- mckoder (21/22) Jun 26 2017 As suggested by the post in above link I searched for "Walter
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (7/17) Jun 25 2017 I think the reason it didn't work out for C++ to specify the
- Steven Schveighoffer (22/31) Jun 26 2017 No, checked exceptions leads to this (maybe not for you, but for 90% of
- mckoder (15/29) Jun 26 2017 Why wouldn't you instead write:
- Moritz Maxeiner (17/47) Jun 26 2017 Because that's even worse.
- jag (40/48) Jun 26 2017 Here's an example C# pseudocode to illustrate the problem:
- Moritz Maxeiner (14/60) Jun 26 2017 No need, you can assume the people discussing this are familiar
- crimaniak (5/21) Jun 26 2017 After preparing my message I read tail of the thread and see
- Moritz Maxeiner (10/33) Jun 26 2017 I wouldn't call it a vision, since I personally don't need it.
- Biotronic (4/15) Jun 27 2017 So I have this .dll. How do I specify which exceptions it throws?
- Moritz Maxeiner (16/30) Jun 28 2017 - Static/Dynamic linking: As said in bullet point two above, the
- Marco Leise (9/16) Jul 05 2017 Ah, come one, now that you see the need you can also embrace
- Moritz Maxeiner (14/25) Jul 05 2017 After some more consideration I would be amenable to automatic
- crimaniak (5/15) Jul 06 2017 Not checked in sense of Java, but Java has no deductible
- Marco Leise (12/16) Jul 06 2017 Yep, absolutely clear. Just like "auto a = 1" does not declare
- Moritz Maxeiner (28/42) Jul 06 2017 Red herring.
- Marco Leise (45/70) Jul 07 2017 You are right, it was a red herring. The code example makes it
- Moritz Maxeiner (31/47) Jul 07 2017 The requirement checked exceptions impose on all functions to
- Marco Leise (6/6) Jul 05 2017 In general, I'm of the opinion that DLL API should be fully
- =?UTF-8?Q?Tobias=20M=C3=BCller?= (15/19) Jun 26 2017 It's not at all bad code to write things down that the compiler could
- mckoder (14/29) Jun 27 2017 Bravo! These are very important points!
- Sebastien Alaiwan (21/30) Jun 27 2017 A quote from Uncle Bob about too much static typing and checked
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (9/13) Jun 28 2017 I don't think this is the best argument, if the programmer wants
- Moritz Maxeiner (31/55) Jun 27 2017 Of course it is bad, because the compiler can do it better (no
- mckoder (6/17) Jun 27 2017 You might as well argue that you shouldn't have to declare the
- Moritz Maxeiner (12/33) Jun 27 2017 Of *course* you shouldn't have to (-> auto functions [1]).
- jag (43/43) Jun 27 2017 As Tobias mentioned, there are safety implications to "auto"
- Moritz Maxeiner (18/28) Jun 27 2017 Your example uses variable type inference, which happens on the
- jag (9/14) Jun 27 2017 Can I as a programmer who wants to call a function written by
- Moritz Maxeiner (23/40) Jun 27 2017 * Can I as a programmer who wants to call a function written by
- mckoder (8/13) Jun 27 2017 So to know what exceptions are possible you have to compile the
- Moritz Maxeiner (27/45) Jun 27 2017 That, or do the even faster thing and use what's written in the
- Moritz Maxeiner (9/13) Jun 27 2017 One could even go a bit farther and implement a mixin template
- Jesse Phillips (30/35) Jun 27 2017 I think there is a threshold. For example, personally I am
- Crayo List (8/11) Jun 29 2017 This statement is logically equivalent to "good code can only be
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (3/7) Jun 29 2017 What do you mean? Exceptions that leave a module clearly aren't
- Crayo List (4/11) Jul 03 2017 Correct!
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (2/14) Jul 04 2017 How does "checked" affect whether something is internal or not?
- Crayo List (18/33) Jul 05 2017 int open(string file)
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (7/10) Jul 05 2017 No, the exception spec is part of the interface whether it is in
- Crayo List (9/21) Jul 06 2017 I disagree!
- Biotronic (25/38) Jul 07 2017 Correct. And throwing a different kind of exception changes the
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (5/13) Jun 26 2017 That's a poor argument, this will be caught in code reviews. You
- jmh530 (10/24) Jun 26 2017 Just curious: how are checked exceptions different from setting
- Sebastien Alaiwan (3/11) Jun 26 2017 Checked exceptions allow a lot more precision about what types of
- Guillaume Boucher (19/21) Jun 26 2017 I totally agree that this is a problem with D right now. If you
- Moritz Maxeiner (4/11) Jun 26 2017 I have tried using such Monads in D, but in the end it always
- Guillaume Boucher (6/10) Jun 26 2017 I haven't tried that yet, tbh. visit is nice, but can't always
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (8/10) Jun 26 2017 The C++17 filesystem api provides two alternatives, the standard
- Guillaume Boucher (6/33) Jun 26 2017 Quoting the C++ standard:
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (15/20) Jun 26 2017 The C++ assumption is that exceptions are slow. So what the text
- Sebastien Alaiwan (5/10) Jun 26 2017 This wasn't my point! I don't think there's a problem with D not
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (17/25) Jun 26 2017 I think the basic argument was that if throws-anything is the
- John Colvin (19/20) Jun 26 2017 I wonder what could be done with something like this:
- Moritz Maxeiner (5/21) Jun 26 2017 Yes, that would be a D idiomatic implementation of the function
- jag (6/24) Jun 26 2017 So the only way for a programmer to know what exceptions can be
- Moritz Maxeiner (6/34) Jun 26 2017 As I have pointed out, implementing such a feature for function
- John Colvin (3/31) Jun 27 2017 No, that's completely the opposite of what I was suggesting. It
- crimaniak (46/47) Jun 26 2017 Warning, Google translate is used! (sorry)
- Gary Willoughby (1/1) Jun 27 2017 I think it's important to understand, D is *not* Java.
- Nick Sabalausky (Abscissa) (2/4) Jun 28 2017 Huh? Is it April 1st?
- Jonathan M Davis via Digitalmars-d (15/18) Jul 03 2017 That was kind of my reaction. It has been my impression that while many
I am disappointed that D doesn't have checked exceptions. exceptions. Having programmed extensively in all these languages I can say with confidence that checked exceptions is the most released there was a lot of debate around the topic of checked vs unchecked exceptions and this created an impression that Java's use of checked exceptions was "controversial". In fact it is a feature every modern language should have. Exceptions that can be thrown by a method should be part of the contract of that method. Changing the list of the list of exceptions that can be thrown by a method is just like changing the parameters of the method. This is something that should cause calling code to fail to compile. This will allow you to inspect the calling code and decode how to deal with the new exception. When the exception that can be thrown by a method is not known you don't know what exceptions to catch and what exceptions to pass through to callers. You can't rely on documentation because the documentation is not verified be the compiler and so is not reliable. All you can do is to run the program a few times, see what exceptions you get and handle them. Even if you are able to determine the full list of exceptions using this strategy, a future revision of the called method can throw a new exception bases it is common to see catching the base Exception class because this is the only way to prevent a crash. This causes exceptions to be "swallowed" because higher level code that is actually prepared to handle certain exceptions never get the exception. With Java this problem doesn't exist. When you call a function you know exactly what exceptions can be thrown and you can catch (or pass through) exactly those exceptions. There is no need to catch the base exception class. When you have multiple implementations of an interface (such as database connectivity layer) and each of those implementations can throw a completely disjoint set of exceptions there is no way to write polymorphic code that can recover from errors. exceptions. (See http://www.artima.com/intv/handcuffs.html ) "They're not going to handle any of these exceptions. There's a bottom level exception handler around their message loop. That handler is just going to bring up a dialog that says what went wrong and continue." Also: "The exception handling should be centralized.." In other words, he thinks all people want to do with exceptions is catch the base Exception class and display a message. I have a lot of respect for Anders Hejlsberg (my first programming language was Turbo Pascal) but he is completely wrong on this topic. Regarding the versioning issue discussed by Anders Hejlsberg, my response is that throwing a new exception is like changing the signature of a function. You want callers to be alerted that they need to update their code! This means the calling code should fail to compile until it is updated.
Jun 25 2017
http://forum.dlang.org/post/ullvxbfqeuztwecxcygb forum.dlang.org On Sunday, 25 June 2017 at 17:38:14 UTC, mckoder wrote:I am disappointed that D doesn't have checked exceptions. exceptions. Having programmed extensively in all these languages I can say with confidence that checked exceptions is checked vs unchecked exceptions and this created an impression that Java's use of checked exceptions was "controversial". In fact it is a feature every modern language should have. Exceptions that can be thrown by a method should be part of the contract of that method. Changing the list of the list of exceptions that can be thrown by a method is just like changing the parameters of the method. This is something that should cause calling code to fail to compile. This will allow you to inspect the calling code and decode how to deal with the new exception. When the exception that can be thrown by a method is not known you don't know what exceptions to catch and what exceptions to pass through to callers. You can't rely on documentation because the documentation is not verified be the compiler and so is not reliable. All you can do is to run the program a few times, see what exceptions you get and handle them. Even if you are able to determine the full list of exceptions using this strategy, a future revision of the called method can throw a new exception and cause your program to crash. As a result, in Exception class because this is the only way to prevent a crash. This causes exceptions to be "swallowed" because higher level code that is actually prepared to handle certain exceptions never get the exception. With Java this problem doesn't exist. When you call a function you know exactly what exceptions can be thrown and you can catch (or pass through) exactly those exceptions. There is no need to catch the base exception class. When you have multiple implementations of an interface (such as database connectivity layer) and each of those implementations can throw a completely disjoint set of exceptions there is no way to write polymorphic code that can recover from errors. exceptions. (See http://www.artima.com/intv/handcuffs.html ) "They're not going to handle any of these exceptions. There's a bottom level exception handler around their message loop. That handler is just going to bring up a dialog that says what went wrong and continue." Also: "The exception handling should be centralized.." In other words, he thinks all people want to do with exceptions is catch the base Exception class and display a message. I have a lot of respect for Anders Hejlsberg (my first programming language was Turbo Pascal) but he is completely wrong on this topic. Regarding the versioning issue discussed by Anders Hejlsberg, my response is that throwing a new exception is like changing the signature of a function. You want callers to be alerted that they need to update their code! This means the calling code should fail to compile until it is updated.
Jun 25 2017
On Sunday, 25 June 2017 at 18:00:46 UTC, Eugene Wissner wrote:http://forum.dlang.org/post/ullvxbfqeuztwecxcygb forum.dlang.orgAs suggested by the post in above link I searched for "Walter checked exceptions". I found a few posts where Walter points to an article written by Bruce Eckel. Though the link to Eckel's article no longer works, I am familiar with Eckel's arguments, and I even exchanged emails with Eckel back in 2003 on this topic. Suffice to say I believe Eckel is wrong on this topic. Bruce Eckel argues that checked exceptions forces you to write bad code (catch Exception base class) and Walter mentions this. Eckel is wrong. The opposite is true. Lack of checked exceptions forces you to catch Exception base class in order to prevent crashes. If you know what exceptions are possible then you can catch just those exceptions. If you don't know then you have to rely on testing to find out what exceptions are possible but you will never get an exhaustive list through testing since tests can never be 100% comprehensive for non-trivial programs. So you end up catching Exception base class, thus swallowing exceptions. I good developers, and I can tell you that experience has proven seen in Java code bases.
Jun 26 2017
On Sunday, 25 June 2017 at 17:38:14 UTC, mckoder wrote:Exceptions that can be thrown by a method should be part of the contract of that method. Changing the list of the list of exceptions that can be thrown by a method is just like changing the parameters of the method. This is something that should cause calling code to fail to compile. This will allow you to inspect the calling code and decode how to deal with the new exception.I think the reason it didn't work out for C++ to specify the exceptions is that you need good IDE support for it and C++ was to a large extent a language where people wrote code in basic editors.message. I have a lot of respect for Anders Hejlsberg (my first programming language was Turbo Pascal) but he is completely wrong on this topic.Turbo Pascal as a language was so-so, but the IDE was very productive.
Jun 25 2017
On 6/25/17 1:38 PM, mckoder wrote:I am disappointed that D doesn't have checked exceptions. exceptions. Having programmed extensively in all these languages I can say with confidence that checked exceptions is the most important thing of debate around the topic of checked vs unchecked exceptions and this created an impression that Java's use of checked exceptions was "controversial". In fact it is a feature every modern language should have.No, checked exceptions leads to this (maybe not for you, but for 90% of developers out there): void foo() { functionWithException(); } compiler: foo throws, and you need to handle or declare the exceptions it throws void foo() { try { functionWithException(); } catch(Exception e) {} // shut up compiler } So it ends up defeating the purpose. The exception is not properly handled, either inside or outside the function. You can get into a long discussion if you want, I'm not going there. Bottom line: D *will not* have checked exceptions, Walter has said so many times. If that's a deal killer, you should probably stick with Java. Sorry, don't want to waste your time. -Steve
Jun 26 2017
On Monday, 26 June 2017 at 15:15:54 UTC, Steven Schveighoffer wrote:No, checked exceptions leads to this (maybe not for you, but for 90% of developers out there): void foo() { functionWithException(); } compiler: foo throws, and you need to handle or declare the exceptions it throws void foo() { try { functionWithException(); } catch(Exception e) {} // shut up compiler }Why wouldn't you instead write: void foo() throws Exception // shut up compiler { functionWithException(); } checked exceptions. Here's the point: with checked exceptions good programmers can write good code. Without checked exceptions even good programmers are forced to write bad code. It is impossible to prevent bad programmers from writing bad code, so that should not even be a goal, but enabling good programmers to write good code should be a goal.
Jun 26 2017
On Monday, 26 June 2017 at 15:40:19 UTC, mckoder wrote:On Monday, 26 June 2017 at 15:15:54 UTC, Steven Schveighoffer wrote:Because that's even worse. The `try catch` as least takes responsibility for handling the error - even if it is just intentionally ignoring it. Your version delegates the responsibility up the call chain (which is in and of itself fine), but it - as you even stated - prevents the caller from using checked exceptions, i.e. you're cheating the system.No, checked exceptions leads to this (maybe not for you, but for 90% of developers out there): void foo() { functionWithException(); } compiler: foo throws, and you need to handle or declare the exceptions it throws void foo() { try { functionWithException(); } catch(Exception e) {} // shut up compiler }Why wouldn't you instead write: void foo() throws Exception // shut up compiler { functionWithException(); } defeated checked exceptions.Here's the point: with checked exceptions good programmers can write good code.With checked exceptions any programmer is forced to a) annotate every single function with the complete aggregate of the exceptions that may be thrown by itself or the functions it calls b) violate checked exceptions and limit its callers by marking itself as throwing a parent exception Or, more succinct: You must either manually write things down the compiler could find out in a fraction of the time via static analysis, or cheat the system; both cases are bad code.
Jun 26 2017
On Monday, 26 June 2017 at 17:43:08 UTC, Moritz Maxeiner wrote:class A { public static void startFoo() { if (/* Foo is not installed */) throw new FooNotInstalled(); // ... } } Programmer B calls the above code like this: class B { try { A.startFoo(); } catch (FooNotInstalled) { // Tell user to purchase Foo } } Later programmer A updates his code because there are newer versions of Foo and he needs the newest version: class A { public static void startFoo() { if (/* Foo is not installed */) throw new FooNotInstalled(); if (/* Foo version is too old */) throw new FooVersionTooOld(); // ... } } Now the code written by Programmer B crashes even though it compiles file. That's bad. Had this been Java, programmer would be would be alerted to the fact that he needs to decide what do do if the version of Foo is too old. This is good. So listing exceptions that can be thrown is a good thing because it helps you write more reliable code. If you are lazy you can always defeat the system by declaring your method as throwing a parent (or the root) exception class, in which case it is noHere's the point: with checked exceptions good programmers can write good code.With checked exceptions any programmer is forced to a) annotate every single function with the complete aggregate of the exceptions that may be thrown by itself or the functions it calls b) violate checked exceptions and limit its callers by marking itself as throwing a parent exception
Jun 26 2017
On Monday, 26 June 2017 at 18:31:50 UTC, jag wrote:On Monday, 26 June 2017 at 17:43:08 UTC, Moritz Maxeiner wrote:No need, you can assume the people discussing this are familiar with the issue, it's not new.Here's the point: with checked exceptions good programmers can write good code.With checked exceptions any programmer is forced to a) annotate every single function with the complete aggregate of the exceptions that may be thrown by itself or the functions it calls b) violate checked exceptions and limit its callers by marking itself as throwing a parent exceptionclass A { public static void startFoo() { if (/* Foo is not installed */) throw new FooNotInstalled(); // ... } } Programmer B calls the above code like this: class B { try { A.startFoo(); } catch (FooNotInstalled) { // Tell user to purchase Foo } } Later programmer A updates his code because there are newer versions of Foo and he needs the newest version: class A { public static void startFoo() { if (/* Foo is not installed */) throw new FooNotInstalled(); if (/* Foo version is too old */) throw new FooVersionTooOld(); // ... } } Now the code written by Programmer B crashes even though it compiles file. That's bad. Had this been Java, programmer would be would be alerted to the fact that he needs to decide what do do if the version of Foo is too old. This is good.And the good *way* to achieve this result would be the following: - When visiting `startFoo`, the compiler automatically aggregates all different exceptions it may throw and stores the resulting set - If `startFoo` is going to be part of a (binary) library and its symbol is exported, also export its exception set - Improve the compiler's nothrow analysis such that if startFoo is called in scope S, but all of the exceptions in its exception set are caught (i.e. can't break out of scope S), it is treated as nothrow in S. - Enclose the call to `startFoo` in B in a nothrow scope.So listing exceptions that can be thrown is a good thing because it helps you write more reliable code.It is a bad thing because you force a human to do a machine's job.
Jun 26 2017
On Monday, 26 June 2017 at 19:31:53 UTC, Moritz Maxeiner wrote:And the good *way* to achieve this result would be the following: - When visiting `startFoo`, the compiler automatically aggregates all different exceptions it may throw and stores the resulting set - If `startFoo` is going to be part of a (binary) library and its symbol is exported, also export its exception set - Improve the compiler's nothrow analysis such that if startFoo is called in scope S, but all of the exceptions in its exception set are caught (i.e. can't break out of scope S), it is treated as nothrow in S. - Enclose the call to `startFoo` in B in a nothrow scope.After preparing my message I read tail of the thread and see your vision very close to mine. đź‘ŤThis is a bad necessity, but a necessary opportunity. Sometimes you need to be sure that the compiler's vision matches yours.So listing exceptions that can be thrown is a good thing because it helps you write more reliable code.It is a bad thing because you force a human to do a machine's job.
Jun 26 2017
On Tuesday, 27 June 2017 at 00:29:53 UTC, crimaniak wrote:On Monday, 26 June 2017 at 19:31:53 UTC, Moritz Maxeiner wrote:I wouldn't call it a vision, since I personally don't need it. It's just that I consider checked exceptions as an excuse for not improving a deficient compiler.And the good *way* to achieve this result would be the following: - When visiting `startFoo`, the compiler automatically aggregates all different exceptions it may throw and stores the resulting set - If `startFoo` is going to be part of a (binary) library and its symbol is exported, also export its exception set - Improve the compiler's nothrow analysis such that if startFoo is called in scope S, but all of the exceptions in its exception set are caught (i.e. can't break out of scope S), it is treated as nothrow in S. - Enclose the call to `startFoo` in B in a nothrow scope.After preparing my message I read tail of the thread and see your vision very close to mine. đź‘ŤI would need a concrete example that's not either solved by the steps mentioned in my post, or using compile time introspection on a function's exception set (as shown in John's idiomatic proposal [1]). [1] http://forum.dlang.org/post/lxejskhonjtiifvvgwnd forum.dlang.orgThis is a bad necessity, but a necessary opportunity. Sometimes you need to be sure that the compiler's vision matches yours.So listing exceptions that can be thrown is a good thing because it helps you write more reliable code.It is a bad thing because you force a human to do a machine's job.
Jun 26 2017
On Monday, 26 June 2017 at 19:31:53 UTC, Moritz Maxeiner wrote:the good *way* to achieve this result would be the following: - When visiting `startFoo`, the compiler automatically aggregates all different exceptions it may throw and stores the resulting set - If `startFoo` is going to be part of a (binary) library and its symbol is exported, also export its exception set - Improve the compiler's nothrow analysis such that if startFoo is called in scope S, but all of the exceptions in its exception set are caught (i.e. can't break out of scope S), it is treated as nothrow in S. - Enclose the call to `startFoo` in B in a nothrow scope.So I have this .dll. How do I specify which exceptions it throws? -- Biotronic
Jun 27 2017
On Wednesday, 28 June 2017 at 06:31:40 UTC, Biotronic wrote:On Monday, 26 June 2017 at 19:31:53 UTC, Moritz Maxeiner wrote:- Static/Dynamic linking: As said in bullet point two above, the exception set would have to be exported (more precise: in such a way that it can be loaded again at compile time); there are several ways to go about that: Add the exception set (e.g. via attributes) to the function declarations in a .di file (which could indeed look like checked exception, except that it's auto generated), use a separate (binary) file with mangled functions names to exception set mapping, etc. - Dynamic loading: Won't work One could also make an exception for bodyless functions and allow specification of the exception set *only* there, e.g. --- // Allow "checked exceptions" for stubs only void foo() throws AException throws BException; ---the good *way* to achieve this result would be the following: - When visiting `startFoo`, the compiler automatically aggregates all different exceptions it may throw and stores the resulting set - If `startFoo` is going to be part of a (binary) library and its symbol is exported, also export its exception set - Improve the compiler's nothrow analysis such that if startFoo is called in scope S, but all of the exceptions in its exception set are caught (i.e. can't break out of scope S), it is treated as nothrow in S. - Enclose the call to `startFoo` in B in a nothrow scope.So I have this .dll. How do I specify which exceptions it throws?
Jun 28 2017
Am Wed, 28 Jun 2017 11:04:58 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>:One could also make an exception for bodyless functions and allow specification of the exception set *only* there, e.g. --- // Allow "checked exceptions" for stubs only void foo() throws AException throws BException; ---Ah, come one, now that you see the need you can also embrace it as an option for people who want to add some documentation. void foo() throws AException // When the ant's life ends prematurely throws BException; // When the ant gets distracted by a lady bug -- Marco
Jul 05 2017
On Wednesday, 5 July 2017 at 20:35:14 UTC, Marco Leise wrote:Am Wed, 28 Jun 2017 11:04:58 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>:After some more consideration I would be amenable to automatic inference of the exception set as the default with *optional* manual specification, i.e. --- void foo() throws AException throws BException { ... } vod bar() { foo(); } --- works and bar's exception is inferred by the compiler to contain AException and BException. But to be clear (and the title and description of any DIP addressing this should reflect this): These are not checked exceptions, because checked exceptions would require bar to declare its exception set manually.One could also make an exception for bodyless functions and allow specification of the exception set *only* there, e.g. --- // Allow "checked exceptions" for stubs only void foo() throws AException throws BException; ---Ah, come one, now that you see the need you can also embrace it as an option for people who want to add some documentation.
Jul 05 2017
On Thursday, 6 July 2017 at 01:31:44 UTC, Moritz Maxeiner wrote:--- void foo() throws AException throws BException { ... } vod bar() { foo(); } --- works and bar's exception is inferred by the compiler to contain AException and BException. But to be clear (and the title and description of any DIP addressing this should reflect this): These are not checked exceptions, because checked exceptions would require bar to declare its exception set manually.Not checked in sense of Java, but Java has no deductible exceptions. If compiler will fail on `void bar() { foo(); } throws AException;` we still can call it 'checked', I think. In sense of D.
Jul 06 2017
Am Thu, 06 Jul 2017 01:31:44 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>:But to be clear (and the title and description of any DIP addressing this should reflect this): These are not checked exceptions, because checked exceptions would require bar to declare its exception set manually.Yep, absolutely clear. Just like "auto a = 1" does not declare a variable as we all know declarations start with a type. Instead of defining checked exceptions how it bests fits all your posts in this thread, why not say "Checked exceptions as implemented in Java were a good idea, had they allowed the compiler to infer them where possible." Of course we can still call those inferred checked exceptions something else. ;o) -- Marco
Jul 06 2017
On Thursday, 6 July 2017 at 11:01:26 UTC, Marco Leise wrote:Am Thu, 06 Jul 2017 01:31:44 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>:Red herring. Checked exceptions are well defined - not just implemented - (by Java as the de facto authority for the term) as requiring the declaration of all exceptions (that aren't inherited from some special class, in Java's case `RuntimeException`, in D's it would be `Error`) that may be thrown by a function as a result of its body being executed [1]. If even a single function is allowed to have its exception set defined by inference (instead of declaration), you are not implementing checked exceptions. --- void foo() throws AExp throws BExc { ... } void bar1() { foo(); } // Checked exceptions require this to result in a compilation error void bar2() throws AExc throws BExc { foo(); } // this must be used for checked exceptions ---But to be clear (and the title and description of any DIP addressing this should reflect this): These are not checked exceptions, because checked exceptions would require bar to declare its exception set manually.Yep, absolutely clear. Just like "auto a = 1" does not declare a variable as we all know declarations start with a type.Instead of defining checked exceptions how it bests fits all your posts in this thread, why not say "Checked exceptions as implemented in Java were a good idea, had they allowed the compiler to infer them where possible."Invalid premise. The definition of checked exceptions is de facto fixed by Java [1], because it not only coined the term but remains the only major PL to use them.Of course we can still call those inferred checked exceptions something else. ;o)The java compiler does infer an exception set for every function based on its body. This is then checked against the function's exception set as declared in its signature. "inferred checked exceptions" is thus an oxymoron, because it would mean checking the inferred exception set against itself. [1] https://docs.oracle.com/javase/7/docs/api/java/lang/Exception.html
Jul 06 2017
Am Thu, 06 Jul 2017 13:16:23 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>:On Thursday, 6 July 2017 at 11:01:26 UTC, Marco Leise wrote:You are right, it was a red herring. The code example makes it very obvious that inference means letting the exceptions slip through unchecked and out of main() in the wildest case.Am Thu, 06 Jul 2017 01:31:44 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>: =20=20 Red herring. [=E2=80=A6] =20 --- void foo() throws AExp throws BExc { ... } void bar1() { foo(); } // Checked exceptions require this to=20 result in a compilation error void bar2() throws AExc throws BExc { foo(); } // this must be=20 used for checked exceptions ---But to be clear (and the title and description of any DIP addressing this should reflect this): These are not checked exceptions, because checked exceptions would require bar to declare its exception set manually. =20Yep, absolutely clear. Just like "auto a =3D 1" does not declare a variable as we all know declarations start with a type. =20Invalid premise. The definition of checked exceptions is de facto=20 fixed by Java [1], because it not only coined the term but=20 remains the only major PL to use them.That's right, but still one can distill general ideas and leave implementations details aside. Pretty much like the Platonic Ideal. Then you look at what the complaints are with the current implementation and see if you can satisfy all sides. I don't know if this is any good beyond an example of a different implementation of checked exceptions, but here is one option against the "every function in the call chain accumulates more and more 'throws' declarations": /** * Throws: * ZeroException when i is 0 * NonZeroException when i is not 0 */ void foo(int i) { if (i =3D=3D 0) throw new ZeroException(); throw new NonZeroException(); } void bar(int i) check_exceptions { foo(i); // Error: The following exceptions are not handled: // ZeroException thrown from foo() when i is 0 // NonZeroException thrown from foo() when i is not 0 } I.e. everything stays the same until a programmer needs a verification of what (s)he should/could handle right away, what needs to be wrapped and what can be passed further up the call chain. That's close to impossible now in deeply nested code. Resource unavailability prone to race conditions can often be handled by asking the user to fix the issue and continue for example (including network, disk space, RAM, video encoding hardware slots, exclusive microphone use). In other cases an exception is only thrown when an incorrect argument is passed. Knowing (statically) that you pass only good values you can catch the exception and turn it into an assert instead of passing it up the call chain, potentially allowing the caller to be nothrow. --=20 Marco
Jul 07 2017
On Friday, 7 July 2017 at 18:48:31 UTC, Marco Leise wrote:Am Thu, 06 Jul 2017 13:16:23 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>: That's right, but still one can distill general ideas and leave implementations details aside. Pretty much like the Platonic Ideal. Then you look at what the complaints are with the current implementation and see if you can satisfy all sides.The requirement checked exceptions impose on all functions to declare their respective exception set is not an implementation detail, but part of the definition. With regards to the general ideas: That's what my writing about exception sets, tehir inference, and nothrow analysis were (supposed to be) about. Unless, however, whatever one eventually tries to get into the language (if that is even attempted) conforms to the preexisting definition of checked exceptions (which I'm as certain as I can reasonably be won't make it into D), calling it that will only serve to cloud the issue and alienate people. Personally, I would call a system with the exception set of a function being (optionally) declarable as "declarable exceptions", but that might still be too close to "checked exceptions" not to illicit screams of horror.[...] I.e. everything stays the same until a programmer needs a verification of what (s)he should/could handle right away, what needs to be wrapped and what can be passed further up the call chain. That's close to impossible now in deeply nested code.If one replaces the ` check_exceptions` with `nothrow` the above is essentially what one should get if one enhances the (static) nothrow analysis (as I mentioned in an earlier post) to essentially treat a scope implicitly as nothrow if the aggregated exception set (as determined by the compiler) is empty. Or more succinct: Infer `nothrow` for normal functions, as well.In other cases an exception is only thrown when an incorrect argument is passed. Knowing (statically) that you pass only good values you can catch the exception and turn it into an assert instead of passing it up the call chain, potentially allowing the caller to be nothrow.There are two cases here: - the function takes untrusted user data: Violations are valid runtime behaviour -> Exceptions, error codes, split in validation and processing function pair with the second being executed only after the first has successfully validated the input data (and thus transformed it into trusted program data), etc. - the function takes trusted program data: Violations are bugs -> assert, Error, DbC, etc.
Jul 07 2017
In general, I'm of the opinion that DLL API should be fully explicit. It's the only way you can reasonably provide ABI stability. That means no templates, no attribute inference and explicit exception lists if the compiler were to used them. -- Marco
Jul 05 2017
Moritz Maxeiner <moritz ucworks.org> wrote:[...] Or, more succinct: You must either manually write things down the compiler could find out in a fraction of the time via static analysis, or cheat the system; both cases are bad code.It's not at all bad code to write things down that the compiler could infer, quite the opposite. Writing it down signals _intent_ and the compiler can check if the implementation is matching the specification which gives you additional security. Additionally it allowes the compiler to do the checks locally which is much easier. Function signatures are interfaces which should be self-contained IMO, i.e. it should not be necessary to examine the function body. That's what signatures are for. At very least for public interfaces. I honestly don't understand how people that care a great deal about expressive type systems can be so opposed to checked exceptions. After all they wouldn't use 'object' for everything either. Tobi
Jun 26 2017
On Tuesday, 27 June 2017 at 06:10:52 UTC, Tobias MĂĽller wrote:It's not at all bad code to write things down that the compiler could infer, quite the opposite. Writing it down signals _intent_ and the compiler can check if the implementation is matching the specification which gives you additional security. Additionally it allowes the compiler to do the checks locally which is much easier. Function signatures are interfaces which should be self-contained IMO, i.e. it should not be necessary to examine the function body. That's what signatures are for. At very least for public interfaces. I honestly don't understand how people that care a great deal about expressive type systems can be so opposed to checked exceptions. After all they wouldn't use 'object' for everything either.Bravo! These are very important points! FWIW, Bruce Eckel who is so often quoted by people who are opposed to checked exceptions comes from a dynamic language background. Here's a relevant quote by Bruce Eckel: "I think that the belief that everything needs strong static (compile-time) checking is an illusion; it seems like it will buy you more than it actually does. But this is a hard thing to see if you are coming from a statically-typed language." Source: https://groups.google.com/forum/#!original/comp.lang.java.advocacy/r8VPk4deYDI/qqhL8g1uvf8J If you like dynamic languages such as Python you probably agree with Bruce Eckel. If you are a fan of static checking then I don't see how you can like that.
Jun 27 2017
On Tuesday, 27 June 2017 at 10:18:04 UTC, mckoder wrote:"I think that the belief that everything needs strong static (compile-time) checking is an illusion; it seems like it will buy you more than it actually does. But this is a hard thing to see if you are coming from a statically-typed language." Source: https://groups.google.com/forum/#!original/comp.lang.java.advocacy/r8VPk4deYDI/qqhL8g1uvf8J If you like dynamic languages such as Python you probably agree with Bruce Eckel. If you are a fan of static checking then I don't see how you can like that.A quote from Uncle Bob about too much static typing and checked exceptions: http://blog.cleancoder.com/uncle-bob/2017/01/11/TheDarkPath.html "My problem is that [Kotlin and Swift] have doubled down on strong static typing. Both seem to be intent on closing every single type hole in their parent languages." "I would not call Java a strongly opinionated language when it comes to static typing. You can create structures in Java that follow the type rules nicely; but you can also violate many of the type rules whenever you want or need to. The language complains a bit when you do; and throws up a few roadblocks; but not so many as to be obstructionist. Swift and Kotlin, on the other hand, are completely inflexible when it comes to their type rules. For example, in Swift, if you declare a function to throw an exception, then by God every call to that function, all the way up the stack, must be adorned with a do-try block, or a try!, or a try?. There is no way, in this language, to silently throw an exception all the way to the top level; without paving a super-hiway for it up through the entire calling tree."
Jun 27 2017
On Tuesday, 27 June 2017 at 16:54:08 UTC, Sebastien Alaiwan wrote:adorned with a do-try block, or a try!, or a try?. There is no way, in this language, to silently throw an exception all the way to the top level; without paving a super-hiway for it up through the entire calling tree."I don't think this is the best argument, if the programmer wants to reduce the number of exceptions that are propagated then the exception should be recast to a more abstract exception between module boundaries. So the "super highway" issue is more a result of the programmer not being interested in structuring error-handling, but rather view errors as something that never should happen. Which may make sense in some applications, but not in all.
Jun 28 2017
On Tuesday, 27 June 2017 at 06:10:52 UTC, Tobias MĂĽller wrote:Moritz Maxeiner <moritz ucworks.org> wrote:Of course it is bad, because the compiler can do it better (no chance for a wrong exception set sans compiler bugs) and faster than you.[...] Or, more succinct: You must either manually write things down the compiler could find out in a fraction of the time via static analysis, or cheat the system; both cases are bad code.It's not at all bad code to write things down that the compiler could infer, quite the opposite.Writing it down signals _intent_ and the compiler can check if the implementation is matching the specificationVerifying that a function meets its specification is what unittests are for (asserts for runtime behaviour, static asserts for types). With a function set trait there's nothing stopping you from writing a template that allows you to do the following: --- void foo() { ... } unittest { static assert (throws!(foo, AException)); static assert (throwsAll!(foo, AException, BException)); static assert (throwsAny!(foo, AException, CException)); static assert (!throws!(foo, CException)); } --- which would be idiomatic D, giving you not only the same guarantees as checked exceptions (without the downsides), but also even more versatility by allowing arbitrary checks on the exception set.which gives you additional security.This has nothing to do with security; you may be thinking of safety.Additionally it allowes the compiler to do the checks locally which is much easier.Easier to implement in the compiler, yes. That's precisely why I called it a compiler deficiency compared to exposing the function exception set, which is more advanced.Function signatures are interfaces which should be self-contained IMO, i.e. it should not be necessary to examine the function body. That's what signatures are for. At very least for public interfaces.Sure, but since a function's signature in D does not include its exception set (be they checked or not), that point is moot.I honestly don't understand how people that care a great deal about expressive type systems can be so opposed to checked exceptions. After all they wouldn't use 'object' for everything either.For exactly the reasons I have already explained.
Jun 27 2017
On Tuesday, 27 June 2017 at 11:40:02 UTC, Moritz Maxeiner wrote:You might as well argue that you shouldn't have to declare the return type of functions because the compiler can determine that automatically based on the types of values you are actually returning. Then write unit tests to make sure that the return type as determined by the compiler matches what you intended.It's not at all bad code to write things down that the compiler could infer, quite the opposite.Of course it is bad, because the compiler can do it better (no chance for a wrong exception set sans compiler bugs) and faster than you.Writing it down signals _intent_ and the compiler can check if the implementation is matching the specificationVerifying that a function meets its specification is what unittests are for (asserts for runtime behaviour, static asserts for types).
Jun 27 2017
On Tuesday, 27 June 2017 at 16:01:37 UTC, mckoder wrote:On Tuesday, 27 June 2017 at 11:40:02 UTC, Moritz Maxeiner wrote:Of *course* you shouldn't have to (-> auto functions [1]). The difference being, of course, that specifying the return type is always only a single type, whereas specifying the exception set blows up in verbosity with each additional level of call hierarchy.You might as well argue that you shouldn't have to declare the return type of functions because the compiler can determine that automatically based on the types of values you are actually returning.It's not at all bad code to write things down that the compiler could infer, quite the opposite.Of course it is bad, because the compiler can do it better (no chance for a wrong exception set sans compiler bugs) and faster than you.Writing it down signals _intent_ and the compiler can check if the implementation is matching the specificationVerifying that a function meets its specification is what unittests are for (asserts for runtime behaviour, static asserts for types).Then write unit tests to make sure that the return type as determined by the compiler matches what you intended.If you don't trust the compiler's return type inference you can do that, of course. Though in contrast to the exception set there's a lot less reason to do so in the return type case, because it's only a single type not an arbitrarily large set of types. [1] https://dlang.org/spec/function.html#auto-functions
Jun 27 2017
As Tobias mentioned, there are safety implications to "auto" feature: class A { public static Employee getFoo() { return getPoorPerformingEmployee(); } } This is your code, in which you are calling A which was written by someone else: class B { var foo = A.getFoo(); foo.fire(); } Now another programmer changes class A as follows: class A { public static Missile getFoo() { return new Missile(); } } Guess what happens now? You intended to fire an employee, but instead you have fired a missile. The compiler did not catch this grave mistake because you did not clearly state your intent. Your class B compiles fine because both Employee and Missile have a method named fire(). You could have expressed your intent more clearly like this: class B { Employee foo = A.getFoo(); foo.fire(); } Now the compiler is able to catch your mistake. This is the reason your code becomes safer when you express your intent clearly. You should have the option to state your intent clearly by listing the exceptions that can be thrown by a method. In dynamic languages like Python there is less ability to state intent clearly. As a result in such languages fewer bugs can be caught at compile time. More bugs show up at run time. This may be acceptable if the program is intended for internal use in a company, because when the program crashes they can call you to come and fix it because you are in the next office. But when reliability is important then the more opportunity there is to express intent and have the compiler verify your code against your intent, the better.
Jun 27 2017
On Tuesday, 27 June 2017 at 18:14:47 UTC, jag wrote:As Tobias mentioned, there are safety implications to "auto" feature: [...]Your example uses variable type inference, which happens on the *caller* side, *not* the *callee* side, the latter of which being where both checked exceptions and return type inference happen. The correct analogue to your example in the exception domain is thus *not* checked exceptions, but verifying the exception set *at the call site* (the same way you fix the variable type *at the call site* to `Employee`), which is exactly what you can do by exposing the function exception set via a trait.Now the compiler is able to catch your mistake. This is the reason your code becomes safer when you express your intent clearly. You should have the option to state your intent clearly by listing the exceptions that can be thrown by a method.As I have pointed out, your example occurs on the *caller* side, not the *callee* side. The proper solution is not for the callee to specify which exceptions it may throw, but for the caller to specify which exceptions it allows the callee to throw (using compile time introspection on the exception set).In dynamic languages like Python [...]None of this justifies putting the burden on the callee side (i.e. checked exceptions), instead of on the caller side (the latter being implementable in an idiomatic way using a trait as John has proposed).
Jun 27 2017
On Tuesday, 27 June 2017 at 19:37:24 UTC, Moritz Maxeiner wrote:As I have pointed out, your example occurs on the *caller* side, not the *callee* side. The proper solution is not for the callee to specify which exceptions it may throw, but for the caller to specify which exceptions it allows the callee to throw (using compile time introspection on the exception set).Can I as a programmer who wants to call a function written by someone else inspect the declaration of that function and know what exceptions are possible? If no how is this supposed to work? I am supposed to specify that exceptions I want to allow the called function to throw? The called function is not going to dynamically adapt itself and change the list of exceptions it throws, right? So how can I know, before running the code, what exceptions are possible?
Jun 27 2017
On Tuesday, 27 June 2017 at 21:47:49 UTC, jag wrote:On Tuesday, 27 June 2017 at 19:37:24 UTC, Moritz Maxeiner wrote:* Can I as a programmer who wants to call a function written by someone else inspect that function's exception set? Yes, as explained fully here [1], shown as an idiomatic D trait here [2], and a template based abstraction around that trait here [3]. It would need to be implemented, of course, but it's not conceptually hard.As I have pointed out, your example occurs on the *caller* side, not the *callee* side. The proper solution is not for the callee to specify which exceptions it may throw, but for the caller to specify which exceptions it allows the callee to throw (using compile time introspection on the exception set).Can I as a programmer who wants to call a function written by someone else inspect the declaration of that function and know what exceptions are possible?If no how is this supposed to work?It was explained multiple times in this thread.I am supposed to specify that exceptions I want to allow the called function to throw?You aren't supposed to do anything, but you can do that, yes.The called function is not going to dynamically adapt itself and change the list of exceptions it throws, right?What? A function's exception set is determined by its body and can be aggregated by the compiler in a single recursive pass in the static analysis phase.So how can I know, before running the code, what exceptions are possible?You mean the very first time you want to call it and you don't know the exception set yourself by looking at its signature? Put the call in a nothrow scope and compile the module (which is fast in D), the compiler will then complain which exceptions you didn't catch (requires improvement of nothrow analysis [1]). [1] http://forum.dlang.org/post/uovtkvpdagzagzhyacbp forum.dlang.org [2] http://forum.dlang.org/post/lxejskhonjtiifvvgwnd forum.dlang.org [3] http://forum.dlang.org/post/fjjkqbxiznlxfstqntnv forum.dlang.org
Jun 27 2017
On Tuesday, 27 June 2017 at 22:56:47 UTC, Moritz Maxeiner wrote:You mean the very first time you want to call it and you don't know the exception set yourself by looking at its signature? Put the call in a nothrow scope and compile the module (which is fast in D), the compiler will then complain which exceptions you didn't catch (requires improvement of nothrow analysis [1]).So to know what exceptions are possible you have to compile the code? I consider that inferior to other solutions such as callee explicitly stating what exceptions it may throw, because then all you have to do is glance at the callee. Also, I think explicitly stating your intent in this manner (by the callee not just the caller) is a good idea, to make sure you are not throwing some exception you didn't mean to throw.
Jun 27 2017
On Wednesday, 28 June 2017 at 01:35:32 UTC, mckoder wrote:On Tuesday, 27 June 2017 at 22:56:47 UTC, Moritz Maxeiner wrote:That, or do the even faster thing and use what's written in the documentation (which a sensible person might generate automatically, embedding the generated exception set for each function). There are only two outcomes (sans compiler bugs): - What's written there is correct -> It will compile and you're fine - What's written there is incorrect -> It won't compile and tell you what's missing In the 2nd case you have discovered a bug in whatever codebase you are using. Report it.You mean the very first time you want to call it and you don't know the exception set yourself by looking at its signature? Put the call in a nothrow scope and compile the module (which is fast in D), the compiler will then complain which exceptions you didn't catch (requires improvement of nothrow analysis [1]).So to know what exceptions are possible you have to compile the code?I consider that inferior to other solutions such as callee explicitly stating what exceptions it may throw, because then all you have to do is glance at the callee.On the one hand you have a small one-time cost (I would go as far as calling it tiny, since I consider it a reasonable assumption for you to have the documentation open), on the other hand you have a one-time cost with its size depending on the call hierarchy level and small constant maintenance costs on every change. If you consider the first inferior to the second, that's your call, but I disagree strongly. That being said, nothing prevents you from putting it there anyway: --- static assert (throwsExactly!(foo, AException, BException)); void foo() { ... } ---Also, I think explicitly stating your intent in this manner (by the callee not just the caller) is a good idea, to make sure you are not throwing some exception you didn't mean to throw.Add a static assert as shown above and you're done.
Jun 27 2017
On Wednesday, 28 June 2017 at 02:09:40 UTC, Moritz Maxeiner wrote:--- static assert (throwsExactly!(foo, AException, BException)); void foo() { ... } ---One could even go a bit farther and implement a mixin template using `typeof(this)` and do: --- void foo() { mixin ThrowsExactly!(AException, BException); } ---
Jun 27 2017
On Tuesday, 27 June 2017 at 06:10:52 UTC, Tobias MĂĽller wrote:I honestly don't understand how people that care a great deal about expressive type systems can be so opposed to checked exceptions. After all they wouldn't use 'object' for everything either. TobiI think there is a threshold. For example, personally I am against the compiler refusing to compile because of an unused variable, or import clause. Why, because they get in the way of making changes. I don't want to pacify the compiler as I progress through the development process. Generally when the compiler complains about a type mismatch I actually forgot to make additional changes to make the new thing work. Checked exceptions do the same thing. Call a new function, propagate the exception just to determine if it is a desired change. This very much can lead to attempting to pacify without properly handling. This discussion seems to emphasize the ability to handle every exception type. There are certainly times I've utilized the ability to handle different types of exception in different ways, but it isn't the norm. This is likely because generally I find Exception to crop up because of programming logic bugs rather than true exceptions and in the other cases I'm not using the type of exception to change how I deal with a problem; if my Json parsing throws a Conversion exception I'm not going to handle it differently than when it throws an Invalid Token exception. I however don't have much experience managing checked Exceptions. I remember back in the day trying to fix the long list of exceptions my functions could throw. I'd commonly use throws Exception, pondered on wrapping exceptions into my own exception that would then be thrown. Neither of these would be helpful to the original points, adding exceptions should break the contract and you should be able to catch specific exceptions. How is the ever expanding exception list of static void Main managed by others?
Jun 27 2017
On Monday, 26 June 2017 at 15:40:19 UTC, mckoder wrote:Here's the point: with checked exceptions good programmers can write good code. Without checked exceptions even good programmers are forced to write bad code.This statement is logically equivalent to "good code can only be written with checked exceptions (presumably using Java), all other code is bad". Checked exceptions are a horrible idea because they leak internal implementation details as part of the signature of a method directly and in a transitive manner, which of course is one huge aberration!
Jun 29 2017
On Thursday, 29 June 2017 at 19:34:22 UTC, Crayo List wrote:Checked exceptions are a horrible idea because they leak internal implementation details as part of the signature of a method directly and in a transitive manner, which of course is one huge aberration!What do you mean? Exceptions that leave a module clearly aren't internal implementation details…
Jun 29 2017
On Thursday, 29 June 2017 at 21:06:12 UTC, Ola Fosheim Grøstad wrote:On Thursday, 29 June 2017 at 19:34:22 UTC, Crayo List wrote:Correct! But I said 'checked exceptions' are.Checked exceptions are a horrible idea because they leak internal implementation details as part of the signature of a method directly and in a transitive manner, which of course is one huge aberration!What do you mean? Exceptions that leave a module clearly aren't internal implementation details…
Jul 03 2017
On Monday, 3 July 2017 at 20:22:39 UTC, Crayo List wrote:On Thursday, 29 June 2017 at 21:06:12 UTC, Ola Fosheim Grøstad wrote:How does "checked" affect whether something is internal or not?On Thursday, 29 June 2017 at 19:34:22 UTC, Crayo List wrote:Correct! But I said 'checked exceptions' are.Checked exceptions are a horrible idea because they leak internal implementation details as part of the signature of a method directly and in a transitive manner, which of course is one huge aberration!What do you mean? Exceptions that leave a module clearly aren't internal implementation details…
Jul 04 2017
On Tuesday, 4 July 2017 at 10:14:11 UTC, Ola Fosheim Grøstad wrote:On Monday, 3 July 2017 at 20:22:39 UTC, Crayo List wrote:int open(string file) { if(!exists(file)) throw new SomeException; ... } a few weeks later; int open(string file) { if(file == null) threw new NullSomethingException; same as before } What happens to the 3000 direct and indirect calls to open() ? Notice how the 'interface' has not changed, only the implementation.On Thursday, 29 June 2017 at 21:06:12 UTC, Ola Fosheim Grøstad wrote:How does "checked" affect whether something is internal or not?On Thursday, 29 June 2017 at 19:34:22 UTC, Crayo List wrote:Correct! But I said 'checked exceptions' are.Checked exceptions are a horrible idea because they leak internal implementation details as part of the signature of a method directly and in a transitive manner, which of course is one huge aberration!What do you mean? Exceptions that leave a module clearly aren't internal implementation details…
Jul 05 2017
On Wednesday, 5 July 2017 at 15:48:33 UTC, Crayo List wrote:What happens to the 3000 direct and indirect calls to open() ? Notice how the 'interface' has not changed, only the implementation.No, the exception spec is part of the interface whether it is in the function declaration or not. Such a change could be fatal in any system. What you should do is to specify what Exceptions are thrown across module borders. That means you should recast the internal exceptions into module-level exceptions.
Jul 05 2017
On Wednesday, 5 July 2017 at 21:05:04 UTC, Ola Fosheim Grøstad wrote:On Wednesday, 5 July 2017 at 15:48:33 UTC, Crayo List wrote:I disagree! Once an interface is defined you should be able to alter the implementation all you want without impacting client code!What happens to the 3000 direct and indirect calls to open() ? Notice how the 'interface' has not changed, only the implementation.No, the exception spec is part of the interface whether it is in the function declaration or not.Such a change could be fatal in any system.No idea what you mean here.What you should do is to specify what Exceptions are thrown across module borders. That means you should recast the internal exceptions into module-level exceptions.I don't need to do anything since I don't have a problem. I don't understand what are you helping me with. I pointed out how checked exceptions 'leak' internal implementation, that was all.
Jul 06 2017
On Thursday, 6 July 2017 at 14:59:10 UTC, Crayo List wrote:On Wednesday, 5 July 2017 at 21:05:04 UTC, Ola Fosheim Grøstad wrote:Correct. And throwing a different kind of exception changes the interface, and *does* impact client code. Consider: void fun() { try { gun(); } catch (GoodException goodEx) { // Ignore } catch (Exception badEx) { FireZeeMissiles(); } } void gun() { throw new GoodException (); } Now J. Random Programmer decides to change gun()'s implementation: void gun() { throw new BadException(); } If your assertion that this doesn't change the interface and doesn't impact the client is correct, no missiles will be fired. Sadly, this is not the case, and Switzerland is now wiped off the map. -- BiotronicOn Wednesday, 5 July 2017 at 15:48:33 UTC, Crayo List wrote:I disagree! Once an interface is defined you should be able to alter the implementation all you want without impacting client code!What happens to the 3000 direct and indirect calls to open() ? Notice how the 'interface' has not changed, only the implementation.No, the exception spec is part of the interface whether it is in the function declaration or not.
Jul 07 2017
On Monday, 26 June 2017 at 15:15:54 UTC, Steven Schveighoffer wrote:void foo() { try { functionWithException(); } catch(Exception e) {} // shut up compiler } So it ends up defeating the purpose. The exception is not properly handled, either inside or outside the function.That's a poor argument, this will be caught in code reviews. You might as well use the same argument against returning error codes or optionals. Yes, it is possible to ignore them… and?
Jun 26 2017
On Monday, 26 June 2017 at 15:15:54 UTC, Steven Schveighoffer wrote:No, checked exceptions leads to this (maybe not for you, but for 90% of developers out there): void foo() { functionWithException(); } compiler: foo throws, and you need to handle or declare the exceptions it throws void foo() { try { functionWithException(); } catch(Exception e) {} // shut up compiler }Just curious: how are checked exceptions different from setting nothrow as the default? Like you would have to write: void foo() maythrow { functionWithException(); } So for instance, you could still use your "//shut up compiler" code with the nothrow default.
Jun 26 2017
On Monday, 26 June 2017 at 16:35:51 UTC, jmh530 wrote:Just curious: how are checked exceptions different from setting nothrow as the default? Like you would have to write: void foo() maythrow { functionWithException(); } So for instance, you could still use your "//shut up compiler" code with the nothrow default.Checked exceptions allow a lot more precision about what types of exceptions a function can throw.
Jun 26 2017
On Monday, 26 June 2017 at 16:52:22 UTC, Sebastien Alaiwan wrote:Checked exceptions allow a lot more precision about what types of exceptions a function can throw.I totally agree that this is a problem with D right now. If you want to catch all errors, how are you supposed to remember what std.file.readText throws? Or std.file.mkdir? There are two solutions to this problem that I know of: A) Checked exceptions B) Error codes that can't be implicitly ignored Java uses A, Rust/Go use B. C++ uses B to some extend (e.g. in std::experimental::filesystem). In my opinion, option B better than A because checked exceptions are incredibly verbose. However, both are better than nothing (which is the current state of D right now). It is very well possible to use option B in D. The most convenient one is making functions nothrow and use Algebraic!(T, ErrorCode), or, for void functions, have a parameter "ref ErrorCode". If all functions in Phobos would either follow that pattern or provide an alternative nothrow overload, I would consider that problem solved.
Jun 26 2017
On Monday, 26 June 2017 at 17:44:15 UTC, Guillaume Boucher wrote:It is very well possible to use option B in D. The most convenient one is making functions nothrow and use Algebraic!(T, ErrorCode), or, for void functions, have a parameter "ref ErrorCode". If all functions in Phobos would either follow that pattern or provide an alternative nothrow overload, I would consider that problem solved.I have tried using such Monads in D, but in the end it always ended up being too verbose or too hard to read compared to using exceptions or even simple error codes (with 0 == no error).
Jun 26 2017
On Monday, 26 June 2017 at 17:50:47 UTC, Moritz Maxeiner wrote:I have tried using such Monads in D, but in the end it always ended up being too verbose or too hard to read compared to using exceptions or even simple error codes (with 0 == no error).I haven't tried that yet, tbh. visit is nice, but can't always be used. So I guess unless D introduces syntax for pattern matching, it will always be verbose. In that case a reference to an error code would be the most viable design in D.
Jun 26 2017
On Monday, 26 June 2017 at 17:44:15 UTC, Guillaume Boucher wrote:Java uses A, Rust/Go use B. C++ uses B to some extend (e.g. in std::experimental::filesystem).The C++17 filesystem api provides two alternatives, the standard filesystem_error exception and an output-paramater for capturing os-specific error codes. I'm not quite sure why they provide both, but I guess performance and the ability to compile for runtimes with exceptions turned off could explain it. It is rather clear though that C++ std lib relies heavily on exceptions.
Jun 26 2017
On Monday, 26 June 2017 at 18:42:24 UTC, Ola Fosheim Grøstad wrote:On Monday, 26 June 2017 at 17:44:15 UTC, Guillaume Boucher wrote:Quoting the C++ standard:Java uses A, Rust/Go use B. C++ uses B to some extend (e.g. in std::experimental::filesystem).The C++17 filesystem api provides two alternatives, the standard filesystem_error exception and an output-paramater for capturing os-specific error codes. I'm not quite sure why they provide both, but I guess performance and the ability to compile for runtimes with exceptions turned off could explain it.Filesystem library functions often provide two overloads, one that throws an exception to report file system errors, and another that sets an error_code. [Note: This supports two common use cases: - Uses where file system errors are truly exceptional and indicate a serious failure. Throwing an exception is an appropriate response. - Uses where file system errors are routine and do not necessarily represent failure. Returning an error code is the most appropriate response. This allows application specific error handling, including simply ignoring the error. -- end note]I would say that the overload without exceptions is the "standard" one.It is rather clear though that C++ std lib relies heavily on exceptions.[Citation needed]
Jun 26 2017
On Monday, 26 June 2017 at 21:00:24 UTC, Guillaume Boucher wrote:I would say that the overload without exceptions is the "standard" one.The C++ assumption is that exceptions are slow. So what the text you referenced says is that it provides an alternative mechanism for situations where you are testing for failure, e.g. accessing something that isn't present to see if it exists. It is a performance/convenience alternative. Although that "nothrow design" is rather clumsy and inconvenient since you have to provide the error object yourself as a parameter.No citation needed. RAII + exceptions has been extensively described by Stroustrup as a main code structuring mechanism for C++ since the 1980s. Basic data structures like std::vector is designed with that in mind. C++ programmers that turn off exceptions also have to be careful with many areas of C++ std::lib.It is rather clear though that C++ std lib relies heavily on exceptions.[Citation needed]
Jun 26 2017
On Monday, 26 June 2017 at 17:44:15 UTC, Guillaume Boucher wrote:On Monday, 26 June 2017 at 16:52:22 UTC, Sebastien Alaiwan wrote:This wasn't my point! I don't think there's a problem with D not having CE. I was just pointing out the difference between "nothrow" specifications and CE.Checked exceptions allow a lot more precision about what types of exceptions a function can throw.I totally agree that this is a problem with D right now.
Jun 26 2017
On Monday, 26 June 2017 at 16:35:51 UTC, jmh530 wrote:Just curious: how are checked exceptions different from setting nothrow as the default? Like you would have to write: void foo() maythrow { functionWithException(); } So for instance, you could still use your "//shut up compiler" code with the nothrow default.I think the basic argument was that if throws-anything is the default expectation then people won't feel like silencing thrown exceptions, but allow them to propagate freely. Of course, if the function is marked nothrow then they still will have to silence any exceptions before returning, so same issue. But, I am pretty convinced that this has more to do with tooling than usability. If the tooling is not created with evolving exceptions spec in mind then it becomes tedious to update the throw specification for functions higher up in the call-chain. Another issue is that a function that takes a lambda/function as parameters will have to cover any exception that the parameter lambdas/function can throw as well. Which actually might be a good thing, as it forces you to think more clearly about where exceptions originate from: what-if-the-foreign-lambda throws an exception? But it does have implications for how you work.
Jun 26 2017
On Sunday, 25 June 2017 at 17:38:14 UTC, mckoder wrote:I am disappointed that D doesn't have checked exceptions.I wonder what could be done with something like this: void foo(int a) { if (a > 0) throw new BlahException("blah"); throw new BloopException("bloop"); } unittest { // NEW FEATURE HERE alias Exceptions = __traits(thrownTypes, foo); static assert (staticIndexOf!(BlahException, Exceptions) >= 0); static assert (staticIndexOf!(BloopException, Exceptions) >= 0); } I'm imagining one could use that to do quite a lot of what checked exceptions provide.
Jun 26 2017
On Monday, 26 June 2017 at 21:53:57 UTC, John Colvin wrote:On Sunday, 25 June 2017 at 17:38:14 UTC, mckoder wrote:Yes, that would be a D idiomatic implementation of the function exception set I mentioned [1]. [1] http://forum.dlang.org/post/uovtkvpdagzagzhyacbp forum.dlang.orgI am disappointed that D doesn't have checked exceptions.I wonder what could be done with something like this: void foo(int a) { if (a > 0) throw new BlahException("blah"); throw new BloopException("bloop"); } unittest { // NEW FEATURE HERE alias Exceptions = __traits(thrownTypes, foo); } I'm imagining one could use that to do quite a lot of what checked exceptions provide.
Jun 26 2017
On Monday, 26 June 2017 at 21:53:57 UTC, John Colvin wrote:I wonder what could be done with something like this: void foo(int a) { if (a > 0) throw new BlahException("blah"); throw new BloopException("bloop"); } unittest { // NEW FEATURE HERE alias Exceptions = __traits(thrownTypes, foo); static assert (staticIndexOf!(BlahException, Exceptions) >= 0); static assert (staticIndexOf!(BloopException, Exceptions)So the only way for a programmer to know what exceptions can be thrown by a method is by running the code? In Java this is known while you are writing the code, even before you compile the code. And the compiler verifies that you are handling or passing on all possible exceptions. This is important.= 0);} I'm imagining one could use that to do quite a lot of what checked exceptions provide.
Jun 26 2017
On Tuesday, 27 June 2017 at 00:10:32 UTC, jag wrote:On Monday, 26 June 2017 at 21:53:57 UTC, John Colvin wrote:As I have pointed out, implementing such a feature for function exception sets would be *one* component; the others are mentioned here [1]. [1] http://forum.dlang.org/post/uovtkvpdagzagzhyacbp forum.dlang.orgI wonder what could be done with something like this: void foo(int a) { if (a > 0) throw new BlahException("blah"); throw new BloopException("bloop"); } unittest { // NEW FEATURE HERE alias Exceptions = __traits(thrownTypes, foo); static assert (staticIndexOf!(BlahException, Exceptions)So the only way for a programmer to know what exceptions can be thrown by a method is by running the code? In Java this is known while you are writing the code, even before you compile the code. And the compiler verifies that you are handling or passing on all possible exceptions. This is important.= 0);static assert (staticIndexOf!(BloopException, Exceptions)= 0);} I'm imagining one could use that to do quite a lot of what checked exceptions provide.
Jun 26 2017
On Tuesday, 27 June 2017 at 00:10:32 UTC, jag wrote:On Monday, 26 June 2017 at 21:53:57 UTC, John Colvin wrote:No, that's completely the opposite of what I was suggesting. It would all be static (i.e. compile-time) introspection.I wonder what could be done with something like this: void foo(int a) { if (a > 0) throw new BlahException("blah"); throw new BloopException("bloop"); } unittest { // NEW FEATURE HERE alias Exceptions = __traits(thrownTypes, foo); static assert (staticIndexOf!(BlahException, Exceptions)So the only way for a programmer to know what exceptions can be thrown by a method is by running the code? In Java this is known while you are writing the code, even before you compile the code. And the compiler verifies that you are handling or passing on all possible exceptions. This is important.= 0);static assert (staticIndexOf!(BloopException, Exceptions)= 0);} I'm imagining one could use that to do quite a lot of what checked exceptions provide.
Jun 27 2017
On Sunday, 25 June 2017 at 17:38:14 UTC, mckoder wrote:I am disappointed that D doesn't have checked exceptions.Warning, Google translate is used! (sorry) I fully support mckoder with regard to exceptions. This is a great advantage of Java. I think, the problem with the introduction of verified exceptions in D is rather psychological, as the authors and the community mostly came from C++. Indeed, in C++, the checked exceptions failed, but I think this is more a failure of C++ than the ideas of checked exceptions. The Java experience has shown that this is a powerful tool that really helps to write reliable programs. Most of the arguments against exceptions are somewhat similar to the arguments of language lovers with a weak dynamic typing, by which listing argument types seems tedious. The relevant objection is that there is a problem with lambdas. I think everyone who started using the stream API in Java 8 was faced with this problem. But who said that you need to exactly repeat the approach of Java? When I encountered this problem, I tried to write an analog of this API, only with support for exceptions. As a result, the root of the problem was easily identified. In Java, each exception type thrown is an additional method parameter, similar to the input parameters, and there are no variadic templates for them. The correct implementation should have some TypeTuple for all the types thrown. And the possibility of calculating it. The following thoughts should be considered as speculative, I understand that these ideas will not be accepted. Take for start the system adopted in Java. Now add 'throws auto'. This does not mean 'throws Exception'! This means that the compiler must determine what exceptions this method or function throws. Now add a default - all functions where there are no throws are treated like 'throws auto'. What does this give us? The old code without throws continues to work, since exceptions, except for intercepted ones, successfully pop up to main() and are caught by runtime. But as soon as the author began to denote throws or nothrows, he gets all the benefits of the Java exception system. In addition, if the lower layer has changed, the intermediate layers that delegate the exceptions above do not need to be rewritten, only the code that deals directly with the exception processing and declares it with throws or nothrows will be affected. (I think that you should not abuse this, libraries that are supplied as a separate product should still encapsulate the underlying exceptions in their own). In addition, now the specification of 'throws A, B, C' lowered to 'throws ExceptionTypeTyple! (A, B, C)'. What does it give? We easily write templates that work with functions with any number of types of throws exceptions, and this can be handled according to the same rules as the other template parameters of the method.
Jun 26 2017
I think it's important to understand, D is *not* Java.
Jun 27 2017
On 06/25/2017 01:38 PM, mckoder wrote:I am disappointed that D doesn't have checked exceptions.Huh? Is it April 1st?
Jun 28 2017
On Wednesday, June 28, 2017 21:47:56 Nick Sabalausky via Digitalmars-d wrote:On 06/25/2017 01:38 PM, mckoder wrote:That was kind of my reaction. It has been my impression that while many folks initially seem to think that checked exceptions are a good idea, it has generally been accepted by the programming community at large that they are in fact a bad idea. AFAIK, Java is the only language to have checked exceptions, and every language that has come after has avoided them. Regardless, based on what Walter has said previously, I think that it's quite clear that there is zero danger of checked exceptions ever being added to D and thus there is really no need to spend time or energy arguing about it, which is part of why I've essentially ignored this thread (and is probably why a lot of major posters have ignored it). I have too little time to spend on D-related things right now as it is. LOL. On that count, I probably shouldn't even have spent the time to reply to this... - Jonathan M DavisI am disappointed that D doesn't have checked exceptions.Huh? Is it April 1st?
Jul 03 2017