www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Exception programming difficult

reply Marco Leise <Marco.Leise gmx.de> writes:
I just got a bit frustrated and wanted to say that I like working with
Exceptions in Java a lot more. That has to do first but not foremost with the
declaration:

---Java->>

class MyException extends Exception {
  public MyException(String msg) {
    super(msg);
  }
  public MyException(String msg, Throwable next) {
    super(msg, next)
  }
}

<<-Java---
---D->>

class MyException : Exception {
  this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable
next = null) {
    super(msg, file, line, next);
  }
  this(string msg, Throwable next, string file = __FILE__, size_t line =
__LINE__) {
    super(msg, file, line, next);
  }
}

<<-D---

The other think that I'd really like to see is an actual declaration for the
user of a function to see what exceptions can be thrown - also inferred and
checked by the compiler. In Java you cannot compile a function that throws some
(checked) exception and doesn't declare that like this:

---Java->>

void foo() throws MyException {
  throw new MyException("test");
}

<<-Java---

This way you, as the author, are always aware of which Exceptions you handle
inside the function and which may escape. This escalates to callers of the
function as well, so that in the end the public API has an exact list of
possibly thrown exceptions that the user must handle.
I have around a dozen different exceptions in a hierarchy and a few nested
function calls. It's a maintenance horror to keep the DDoc up to date about
thrown Exceptions. It also doesn't check the spelling or offers a link to the
Exceptions.

---D->>

/**
 * Receives a response from the server.
 * 
 * Some explanation of what
 * the function does in detail.
 * 
 * Params:
 *    response = receives the whole response
 * Throws: 
 *    UnexpectedResponseException if the server sent us garbage
 *
 *    UnauthenticatedException we need retry after we have logged in
 *
 *    SecurityException we have to switch to a secure connection for this
 *
 *    DisconnectException the connection was unexpectedly terminated
 * Returns: the associated response code
 */

<<-D---

I know that the Java way isn't perfect, because some lazy people write dummy
exception handlers to silence the errors, but its a worse solution to _not_
notify the user of a function, that it potentially throws exceptions, I think.
So I wish D was explicit about thrown Exceptions.

-- 
Marco
Aug 11 2012
next sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Sun, 12 Aug 2012 05:02:25 +0200
schrieb Marco Leise <Marco.Leise gmx.de>:

 ---D->>
 
 /**
  * Receives a response from the server.
  * 
  * Some explanation of what
  * the function does in detail.
  * 
  * Params:
  *    response = receives the whole response
  * Throws: 
  *    UnexpectedResponseException if the server sent us garbage
  *
  *    UnauthenticatedException we need retry after we have logged in
  *
  *    SecurityException we have to switch to a secure connection for this
  *
  *    DisconnectException the connection was unexpectedly terminated
  * Returns: the associated response code
  */
 int foo(out string response)
 {...}
 
 <<-D---
could become: ---D->> /** * Receives a response from the server. * * Some explanation of what * the function does in detail. * * Params: * response = receives the whole response * Returns: the associated response code */ int foo(out string response) throws UnexpectedResponseException, /// if the server sent us garbage UnauthenticatedException, /// we need retry after we have logged in SecurityException, /// we have to switch to a secure connection for this DisconnectException /// the connection was unexpectedly terminated {...} <<-D-- So there would be no net change in typing required if that is a concern. Callers of the function could inherit from this documentation as well for their "throws" section, so you only have to rewrite the documetation if the reason for the exception needs to be formulated differently or multiple called functions throw the same exception. -- Marco
Aug 11 2012
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 12-Aug-12 07:28, Marco Leise wrote:
 Am Sun, 12 Aug 2012 05:02:25 +0200
 schrieb Marco Leise <Marco.Leise gmx.de>:

 ---D->>

 /**
   * Receives a response from the server.
   *
   * Some explanation of what
   * the function does in detail.
   *
   * Params:
   *    response = receives the whole response
   * Throws:
   *    UnexpectedResponseException if the server sent us garbage
   *
   *    UnauthenticatedException we need retry after we have logged in
   *
   *    SecurityException we have to switch to a secure connection for this
   *
   *    DisconnectException the connection was unexpectedly terminated
   * Returns: the associated response code
   */
 int foo(out string response)
 {...}

 <<-D---
could become: ---D->> /** * Receives a response from the server. * * Some explanation of what * the function does in detail. * * Params: * response = receives the whole response * Returns: the associated response code */ int foo(out string response) throws UnexpectedResponseException, /// if the server sent us garbage UnauthenticatedException, /// we need retry after we have logged in SecurityException, /// we have to switch to a secure connection for this DisconnectException /// the connection was unexpectedly terminated {...} <<-D--
When I see code like this I have one single thought - error codes! Indeed that's what is used in this example, with Exceptions only being convenient (and separate) transport for error codes. So the net progress is creating 1:1 type for each error condition (start counting the lines of code) and then... If I got it right somewhere later foo is supposed to be used like this: try{ ...some_code foo(); ...other code } catch(UnexpectedResponseException) { print error and disconnect this server or retry? } catch(UnauthenticatedException) { print error 2 } catch(SecurityException) { sslFoo(resp); // this one is just awesome ;) } catch(DisconnectException ) { print error 3 & (ask to) reconnect? } Or used a catch all and do type switch Java-style to see if Exception is one of interesting to you types. Needless to say awful again. First SecurityError is gross fiction as you either know to authenticate (need credentials in the interface) or do auto detection (like try HTTPS, then fallback to HTTP). Moreover encoding _cause_ of error in type is useless, end user needs a hint on the proper way to handle error. It's like pointing out a guy who made the mistake and how stupid it is instead of proposing the ways to fix the situation. what I'd expect the code to be is (been discussed before): class NetworkException { property bool transient; // packet lost or whatever, can re-try with the same parameters property bool lost; // need reconnect to restore, server down or disconnected or unexpected input property string msg(); } This reduces all the handling to: catch(NetworkException ne) { if(ne.lost) //ya kill me, but you got the idea ;) goto ReconnectAndRetry; if(ne.transient){ warning("..."); //log failure goto RetryAndCheckTryCount; } error(ne.msg); } Including but not limited to the time when foo's author adds more types to his "throws list". Unlike checked exceptions it won't break build just for the fuck of it *and* it will still work correctly. In fact if we manage to come up with proper reasonable standard exceptions like Network/IO/etc. that everybody derives from error handling would become damn easy with *any* library. -- Olshansky Dmitry
Aug 15 2012
next sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Wed, 15 Aug 2012 23:29:43 +0400
schrieb Dmitry Olshansky <dmitry.olsh gmail.com>:

 When I see code like this I have one single thought - error codes!
 
 Indeed that's what is used in this example, with Exceptions only being 
 convenient (and separate) transport for error codes. So the net progress 
 is creating 1:1 type for each error condition (start counting the lines 
 of code) and then...
 
 If I got it right somewhere later foo is supposed to be used like this:
 try{
 ...some_code
 foo();
 ...other code
 }
 catch(UnexpectedResponseException)
 {
 	print error and disconnect this server or retry?
 }
 catch(UnauthenticatedException)
 {
 	print error 2
 }
 catch(SecurityException)
 {
 	sslFoo(resp); // this one is just awesome ;)
 }
 catch(DisconnectException )
 {
 	print error 3 & (ask to) reconnect?
 }
 
 Or used a catch all and do type switch Java-style to see if Exception is 
 one of interesting to you types.  Needless to say awful again.
 
 First SecurityError is gross fiction as you either know to authenticate 
 (need credentials in the interface) or do auto detection (like try 
 HTTPS, then fallback to HTTP).
 
 Moreover encoding _cause_ of error in type is useless, end user needs a 
 hint on the proper way to handle error. It's like pointing out a guy who 
 made the mistake and how stupid it is instead of proposing the ways to 
 fix the situation.
 
 what I'd expect the code to be is (been discussed before):
 class NetworkException
 {
 	 property bool transient; // packet lost or whatever, can re-try with 
 the same parameters
 	 property bool lost; // need reconnect to restore, server down or 
 disconnected or unexpected input
 	 property string msg();
 }
 
 This reduces all the handling to:
 catch(NetworkException ne)
 {
 	if(ne.lost)
 		//ya kill me, but you got the idea ;)
 		goto ReconnectAndRetry;
 	if(ne.transient){
 		warning("..."); //log failure
 		goto RetryAndCheckTryCount;
 	}
 	error(ne.msg);
 }
 
 Including but not limited to the time when foo's author adds more types 
 to his "throws list". Unlike checked exceptions it won't break build 
 just for the fuck of it *and* it will still work correctly.
 
 In fact if we manage to come up with proper reasonable standard 
 exceptions like Network/IO/etc. that everybody derives from error 
 handling would become damn easy with *any* library.
Just for the fuck of it, huh :) ? Interesting read, do you know an example, probably a standard library of some other language, that offers standard exceptions like this? If I understand you correctly, the idea is to not use distinct error ids (be they codes or exception classes), but a mix of flags. So you'd have pretty much one "catch" with a few "if"s, but with the flags you can decide on the granularity. -- Marco
Aug 17 2012
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 17-Aug-12 11:47, Marco Leise wrote:
[snip]

 Including but not limited to the time when foo's author adds more types
 to his "throws list". Unlike checked exceptions it won't break build
 just for the fuck of it *and* it will still work correctly.

 In fact if we manage to come up with proper reasonable standard
 exceptions like Network/IO/etc. that everybody derives from error
 handling would become damn easy with *any* library.
 Just for the fuck of it, huh :) ?
I'm currently working on Java project part-time (it shows :) ), a small app-specific server that has to pipeline work items back and forth and do it fast. It's damn frustrating to see (and adapt) when your colleges add/remove exception specs of their interface. And even I discover that methods get or lose throws ExceptionX frequently during development.
 Interesting read, do you know an example, probably a standard library of some
other language,
that offers standard exceptions like this? No, but it's about time to innovate. What I know for sure is that other failed to deliver. (C++ STL - failed, Java - see above, .NET appears to be in the same boat - i.e. more exceptions good and any)
 If I understand you correctly, the idea is to not use
distinct error ids (be they codes or exception classes), but a mix of flags. While I think flags would be a very common way to _hint_ on how to correct the error (or current state of system as a whole). I do suspect that some error types may need more then just a flag, but who knows. So you'd have pretty much one "catch" with a few "if"s, but with the flags you can decide on the granularity. Something like that. With ifs you query important properties about error that allow you to pick the best recover decision. The whole propose of flags is to unify only _important_ items for the _decision_ process and hide useless variability (it still goes to message). A comic-book example: Top scientist breaks into Mr. President room and cries: "We are doomed! Crystal oculator was miscalculated, all readings are under 0.6543124312, helerium core just melted!" Now does it mean it's time to evacuate promptly or instead give order to isolate the secret lab and "end" this guy's project? Unless Mr.President has a nice and long lookup table of all (pseudo) scientific terms he has no clue. -- Olshansky Dmitry
Aug 17 2012
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Fri, 17 Aug 2012 12:48:01 +0400
schrieb Dmitry Olshansky <dmitry.olsh gmail.com>:
 [=E2=80=A6]
 Something like that. With ifs you query important properties about error=
=20
 that allow you to pick the best recover decision. The whole propose of=20
 flags is to unify only _important_ items for the _decision_ process and=20
 hide useless variability (it still goes to message).
=20
 A comic-book example:
 Top scientist breaks into Mr. President room and cries:
 "We are doomed! Crystal oculator was miscalculated, all readings are=20
 under 0.6543124312,  helerium core just melted!"
=20
 Now does it mean it's time to evacuate promptly or instead give order to=
=20
 isolate the secret lab and "end" this guy's project? Unless Mr.President=
=20
 has a nice and long lookup table of all (pseudo) scientific terms he has=
=20
 no clue.
I experimented with an enum that combines some error codes into a common ac= tion, like "retry later", "authenticate", "give up", the list goes on. But = for the networking case (and that's why I was asking for an example of a br= oader application) it is actually nice to have exceptions that read like an= FAQ: Am I still connected? Is the error temporary? Now to the president: He might have a technical advisor, that translates th= e scientists explanation. Assume I'd implement an NNTP client. The protocol= allows for sudden state changes by the server, that would cause unexpected= errors. (Reconfiguration of a running server.) It also allows for extensio= ns, that aside from some formalities can add functionality and error codes. The president would be a programmer who is only interested in simple way to= read or post in newsgroups with the library hiding all the minutiae of dif= ferent error codes, detecting supported protocol versions or restoring stat= e on a reconnect (like which newsgroup was selected). The technical advisor may want to make use of an extension for authenticati= on or searching the newsgroup, so he needs to get at all the information an= d also create raw requests with custom error handling. I think WebDAV is on= e such extension of HTTP. --=20 Marco
Aug 17 2012
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 17-Aug-12 14:10, Marco Leise wrote:
 Am Fri, 17 Aug 2012 12:48:01 +0400
 schrieb Dmitry Olshansky <dmitry.olsh gmail.com>:
 […]
 Something like that. With ifs you query important properties about error
 that allow you to pick the best recover decision. The whole propose of
 flags is to unify only _important_ items for the _decision_ process and
 hide useless variability (it still goes to message).

 A comic-book example:
 Top scientist breaks into Mr. President room and cries:
 "We are doomed! Crystal oculator was miscalculated, all readings are
 under 0.6543124312,  helerium core just melted!"

 Now does it mean it's time to evacuate promptly or instead give order to
 isolate the secret lab and "end" this guy's project? Unless Mr.President
 has a nice and long lookup table of all (pseudo) scientific terms he has
 no clue.
I experimented with an enum that combines some error codes into a common action, like "retry later", "authenticate", "give up", the list goes on.
Don't try to combine the _action_ into Exception. If there is definitive action encoded (like re-try) then just do it. If there is uncertainty of what exactly needs to be re-done (failure somewhere deeply nested) then provide a hint on "state/possible recovery". But for the networking case (and that's why I was asking for an example of a broader application) it is actually nice to have exceptions that read like an FAQ: Am I still connected? Is the error temporary? That's what I have shown (see transient & lost). Again exception doesn't know _how_ (no action or it would do it itself) to restore, it just provides nice hints to decision maker that indeed read as FAQ.
 Now to the president: He might have a technical advisor, that translates the
scientists explanation.
Assume I'd implement an NNTP client. The protocol allows for sudden state changes by the server, that would cause unexpected errors. (Reconfiguration of a running server.) Should be part of library's job (technicians of said scientist). It also allows for extensions, that aside from some formalities can add functionality and error codes.
 The president would be a programmer who is only interested in simple way to
read or post in newsgroups with the library hiding all the minutiae of
different error codes, detecting supported protocol versions or restoring state
on a reconnect (like which newsgroup was selected).
 The technical advisor may want to make use of an extension for authentication
or searching the newsgroup,
so he needs to get at all the information and also create raw requests with custom error handling. First of all there are convenience wrappers and there is low-level API. My proposition doesn't hurt this separation at all. And here is where inheritance finally plays it's role. The thing does nest: NNTPException : NetworkExcpetion (lost, transient) NNTPException contains more interesting & specific info (maybe even straight error codes - why not if they are well documented?) So high-level API is constructed from low-level, and it has some simple hardwired logic but by the end of day it just passes through most unexpected exceptions. So president type of programmer just looks at it as NetworkException (as he should, the higher you sit the less you see) and checks easy flags/fields to make global recovery action. The technical savvy type of programmer can use low-level API directly and even catch NNTP exceptions if RFC error codes are needed (and there could be genuine Network errors like connection lost).
I think WebDAV is one such extension of HTTP.
I way incompetent with NNTP. So take the above with a grain of salt. P.S. For some reason Thunderbird flats your paragraphs into a very long lines, split by hand sorry if inaccurate ;). -- Olshansky Dmitry
Aug 17 2012
prev sibling parent reply "foobar" <foo bar.com> writes:
On Wednesday, 15 August 2012 at 19:29:44 UTC, Dmitry Olshansky 
wrote:
 On 12-Aug-12 07:28, Marco Leise wrote:
 Am Sun, 12 Aug 2012 05:02:25 +0200
 schrieb Marco Leise <Marco.Leise gmx.de>:

 ---D->>

 /**
  * Receives a response from the server.
  *
  * Some explanation of what
  * the function does in detail.
  *
  * Params:
  *    response = receives the whole response
  * Throws:
  *    UnexpectedResponseException if the server sent us 
 garbage
  *
  *    UnauthenticatedException we need retry after we have 
 logged in
  *
  *    SecurityException we have to switch to a secure 
 connection for this
  *
  *    DisconnectException the connection was unexpectedly 
 terminated
  * Returns: the associated response code
  */
 int foo(out string response)
 {...}

 <<-D---
could become: ---D->> /** * Receives a response from the server. * * Some explanation of what * the function does in detail. * * Params: * response = receives the whole response * Returns: the associated response code */ int foo(out string response) throws UnexpectedResponseException, /// if the server sent us garbage UnauthenticatedException, /// we need retry after we have logged in SecurityException, /// we have to switch to a secure connection for this DisconnectException /// the connection was unexpectedly terminated {...} <<-D--
When I see code like this I have one single thought - error codes! Indeed that's what is used in this example, with Exceptions only being convenient (and separate) transport for error codes. So the net progress is creating 1:1 type for each error condition (start counting the lines of code) and then... If I got it right somewhere later foo is supposed to be used like this: try{ ...some_code foo(); ...other code } catch(UnexpectedResponseException) { print error and disconnect this server or retry? } catch(UnauthenticatedException) { print error 2 } catch(SecurityException) { sslFoo(resp); // this one is just awesome ;) } catch(DisconnectException ) { print error 3 & (ask to) reconnect? } Or used a catch all and do type switch Java-style to see if Exception is one of interesting to you types. Needless to say awful again. First SecurityError is gross fiction as you either know to authenticate (need credentials in the interface) or do auto detection (like try HTTPS, then fallback to HTTP). Moreover encoding _cause_ of error in type is useless, end user needs a hint on the proper way to handle error. It's like pointing out a guy who made the mistake and how stupid it is instead of proposing the ways to fix the situation. what I'd expect the code to be is (been discussed before): class NetworkException { property bool transient; // packet lost or whatever, can re-try with the same parameters property bool lost; // need reconnect to restore, server down or disconnected or unexpected input property string msg(); } This reduces all the handling to: catch(NetworkException ne) { if(ne.lost) //ya kill me, but you got the idea ;) goto ReconnectAndRetry; if(ne.transient){ warning("..."); //log failure goto RetryAndCheckTryCount; } error(ne.msg); } Including but not limited to the time when foo's author adds more types to his "throws list". Unlike checked exceptions it won't break build just for the fuck of it *and* it will still work correctly. In fact if we manage to come up with proper reasonable standard exceptions like Network/IO/etc. that everybody derives from error handling would become damn easy with *any* library.
IMHO, the suggested NetworkException is a bad design as it weakens one of the goals of exceptions - to document the programmer's intent. This design basically wraps a bunch of flags in a class, adds redundant boilerplate and reduces exceptions to glorified C-style error codes and flags. What's the point of using exceptions here at all if you use if statements and gotos to handle the error anyway? Seems redundant to me. Moreover, I don't agree with encoding the action or even just a hint in the exception. It goes against common logic - the code that generates the error *cannot* know what should be done to handle it - after all if it does know it would handle the error itself. How would you even know to define if a networking error is transient or not? I agree that there are some issues with the common java style design of exceptions. That does not mean we need to go back to ifs and gotos. instead, we need to see how we can improve and refine further the already quite successful exceptions design. One improvement that can be done is something like Nemerle's - Nemerle has pattern matching in the language and the catch clause uses that same mechanism.
Aug 19 2012
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 19-Aug-12 11:04, foobar wrote:
 On Wednesday, 15 August 2012 at 19:29:44 UTC, Dmitry Olshansky wrote:
 On 12-Aug-12 07:28, Marco Leise wrote:
 Am Sun, 12 Aug 2012 05:02:25 +0200
 schrieb Marco Leise <Marco.Leise gmx.de>:

 ---D->>

 /**
  * Receives a response from the server.
  *
  * Some explanation of what
  * the function does in detail.
  *
  * Params:
  *    response = receives the whole response
  * Throws:
  *    UnexpectedResponseException if the server sent us garbage
  *
  *    UnauthenticatedException we need retry after we have logged in
  *
  *    SecurityException we have to switch to a secure connection for
 this
  *
  *    DisconnectException the connection was unexpectedly terminated
  * Returns: the associated response code
  */
 int foo(out string response)
 {...}

 <<-D---
could become: ---D->> /** * Receives a response from the server. * * Some explanation of what * the function does in detail. * * Params: * response = receives the whole response * Returns: the associated response code */ int foo(out string response) throws UnexpectedResponseException, /// if the server sent us garbage UnauthenticatedException, /// we need retry after we have logged in SecurityException, /// we have to switch to a secure connection for this DisconnectException /// the connection was unexpectedly terminated {...} <<-D--
When I see code like this I have one single thought - error codes! Indeed that's what is used in this example, with Exceptions only being convenient (and separate) transport for error codes. So the net progress is creating 1:1 type for each error condition (start counting the lines of code) and then... If I got it right somewhere later foo is supposed to be used like this: try{ ...some_code foo(); ...other code } catch(UnexpectedResponseException) { print error and disconnect this server or retry? } catch(UnauthenticatedException) { print error 2 } catch(SecurityException) { sslFoo(resp); // this one is just awesome ;) } catch(DisconnectException ) { print error 3 & (ask to) reconnect? } Or used a catch all and do type switch Java-style to see if Exception is one of interesting to you types. Needless to say awful again. First SecurityError is gross fiction as you either know to authenticate (need credentials in the interface) or do auto detection (like try HTTPS, then fallback to HTTP). Moreover encoding _cause_ of error in type is useless, end user needs a hint on the proper way to handle error. It's like pointing out a guy who made the mistake and how stupid it is instead of proposing the ways to fix the situation. what I'd expect the code to be is (been discussed before): class NetworkException { property bool transient; // packet lost or whatever, can re-try with the same parameters property bool lost; // need reconnect to restore, server down or disconnected or unexpected input property string msg(); } This reduces all the handling to: catch(NetworkException ne) { if(ne.lost) //ya kill me, but you got the idea ;) goto ReconnectAndRetry; if(ne.transient){ warning("..."); //log failure goto RetryAndCheckTryCount; } error(ne.msg); } Including but not limited to the time when foo's author adds more types to his "throws list". Unlike checked exceptions it won't break build just for the fuck of it *and* it will still work correctly. In fact if we manage to come up with proper reasonable standard exceptions like Network/IO/etc. that everybody derives from error handling would become damn easy with *any* library.
IMHO, the suggested NetworkException is a bad design as it weakens one of the goals of exceptions - to document the programmer's intent.
I've never seen this goal. "document programmer intent?" could you expand on this?
 This design basically wraps a bunch of flags in a class,
This example does show how common flags could be more useful then a bunch of names. Flags in fact are fast way to do sets... adds redundant
 boilerplate
Compared to what? and reduces exceptions to glorified C-style error codes and
 flags.
They are already glorified C-style error codes in Java. And that's something I tried to improve on (see the thread) Obviously the "and flags" is all I get ;) What's the point of using exceptions here at all if you use if
 statements and gotos to handle the error anyway?
These goto's are conceptual, I don't write the entrie program for the sake of brevity. And the point of exceptions is not to use rows of catch instead of rows of ifs. Seems redundant to me.
 Moreover, I don't agree with encoding the action or even just a hint in
 the exception. It goes against common logic - the code that generates
 the error *cannot* know what should be done to handle it - after all if
 it does know it would handle the error itself.
Right it doesn't know the cure-it-all action or it would have done it on its own, I told so in my posts. Also keep in mind that low-level code may know how to handle errors but doing it is not always acceptable or possible at this level. So it passes info up to somewhere above to take the correct action _based_ on information. How would you even know
 to define if a networking error is transient or not?
If it's worth retying later. It's a question of can or cannot be. Hetwork unreachable is pretty much not transient. Resolving host failed - can be a minor glitch. The fact that connection broke also useful to know, so that handler can safe reconnect (if handler thinks it feasible, low-level code can't decide here).
 I agree that there are some issues with the common java style design of
 exceptions. That does not mean we need to go back to ifs and gotos.
First stop riding on gotos, they are long and tired concept. And my design doesn't implies using them, I've put them in example as conceptual handlers instead of writing ...handle condition x... ifs in no way worse then catches on their own. The whole point was - doing tons of error classes is indeed spawning glorified error codes. Bundling together names is in no way better then proving a flag that indicates these bundles.
 instead, we need to see how we can improve and refine further the
 already quite successful exceptions design.
I'd suggest that. In case you missed the design doesn't change a thing in language. It even doesn't change the code that already works. It suggest a specific standard hierarchy that helps unifying error handling. That is something to discover.
 One improvement that can be done is something like Nemerle's - Nemerle
 has pattern matching in the language and the catch clause uses that same
 mechanism.
So you match any of 10 exceptions in one catch. How do you work with resulting object? Examples please. What benefit it has compared to matching 1 sub-root exception type with the field that indicates common information of interest of these 10 exceptions. -- Olshansky Dmitry
Aug 19 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 12, 2012 05:02:25 Marco Leise wrote:
 I know that the Java way isn't perfect, because some lazy people write dummy
 exception handlers to silence the errors, but its a worse solution to _not_
 notify the user of a function, that it potentially throws exceptions, I
 think. So I wish D was explicit about thrown Exceptions.
It's becoming more universally accepted that while checked exceptions seem like a great idea up front, they're ultimately a bad idea: http://www.artima.com/intv/handcuffs.html D has nothrow, which statically verifies that _no_ exceptions are thrown, but that's as close as it's going to get to having checked exceptions. - Jonathan M Davis
Aug 11 2012
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/12/2012 05:02 AM, Marco Leise wrote:
 I just got a bit frustrated and wanted to say that I like working with
Exceptions in Java a lot more. That has to do first but not foremost with the
declaration:

 ---Java->>

 class MyException extends Exception {
    public MyException(String msg) {
      super(msg);
    }
    public MyException(String msg, Throwable next) {
      super(msg, next)
    }
 }

 <<-Java---
 ---D->>

 class MyException : Exception {
    this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable
next = null) {
      super(msg, file, line, next);
    }
    this(string msg, Throwable next, string file = __FILE__, size_t line =
__LINE__) {
      super(msg, file, line, next);
    }
 }

 <<-D---
---D->> class MyException : Exception { mixin GenericExceptionConstructors; } <<-D---
 The other think that I'd really like to see is an actual declaration for the
user of a function to see what exceptions can be thrown - also inferred and
checked by the compiler. In Java you cannot compile a function that throws some
(checked) exception and doesn't declare that like this:

 ---Java->>

 void foo() throws MyException {
    throw new MyException("test");
 }

 <<-Java---

 This way you, as the author, are always aware of which Exceptions you handle
inside the function and which may escape. This escalates to callers of the
function as well, so that in the end the public API has an exact list of
possibly thrown exceptions that the user must handle.
 I have around a dozen different exceptions in a hierarchy and a few nested
function calls. It's a maintenance horror to keep the DDoc up to date about
thrown Exceptions. It also doesn't check the spelling or offers a link to the
Exceptions.

 ...

 I know that the Java way isn't perfect, because some lazy people write dummy
exception handlers to silence the errors,
 but its a worse solution to _not_ notify the user of a function, that it
potentially throws exceptions, I think. So I
 wish D was explicit about thrown Exceptions.
Well, any scheme for explicit exception annotations I can think of is either unsound or impractical. What would you suggest concretely?
Aug 11 2012
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/11/2012 8:02 PM, Marco Leise wrote:
 I know that the Java way isn't perfect, because some lazy people write dummy
 exception handlers to silence the errors, but its a worse solution to _not_
 notify the user of a function, that it potentially throws exceptions, I
 think. So I wish D was explicit about thrown Exceptions.
Read this and see if you change your mind: http://www.mindview.net/Etc/Discussions/CheckedExceptions/ Anyhow, that article is why D does not have exception specifications. Also, please note that C++ dropped exception specifications.
Aug 11 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, August 11, 2012 21:27:43 Walter Bright wrote:
 Anyhow, that article is why D does not have exception specifications. Also,
 please note that C++ dropped exception specifications.
Though it should be noted that exception specifications are _far_ worse than checked exceptions, because they're checked at runtime instead of compile time, and they kill your program if they fail. So, instead of all of the problems that you get with checked exceptions, you get your program killed at runtime when you don't get your code quite right. I think that you're going to have a hard time finding _anyone_ who actually understands what C++'s exception specifications do and still thinks that they're a good idea, whereas you _will_ find people who fully understand checked exceptions and still think that they're a good idea. - Jonathan M Davis
Aug 11 2012
parent "SomeDude" <lovelydear mailmetrash.com> writes:
On Sunday, 12 August 2012 at 04:36:22 UTC, Jonathan M Davis wrote:
 On Saturday, August 11, 2012 21:27:43 Walter Bright wrote:
 Anyhow, that article is why D does not have exception 
 specifications. Also,
 please note that C++ dropped exception specifications.
Though it should be noted that exception specifications are _far_ worse than checked exceptions, because they're checked at runtime instead of compile time, and they kill your program if they fail. So, instead of all of the problems that you get with checked exceptions, you get your program killed at runtime when you don't get your code quite right. I think that you're going to have a hard time finding _anyone_ who actually understands what C++'s exception specifications do and still thinks that they're a good idea, whereas you _will_ find people who fully understand checked exceptions and still think that they're a good idea. - Jonathan M Davis
Yup, I'm among them, and I believe the only problem with checked exceptions is that most people don't understand how to use them. The main problem people have with checked exceptions is that they are forced to handle error/exceptional cases, and therefore to think about them. To my knowledge, there are no absolute rules or truths in error handling, and therefore it seems it throws people in all sorts of perplexity, because when it's not specified, programmers have no idea who is supposed to handle an exception, and how. So the worst offenders wipe them under the rug, which is borderline criminal, because it can make it nearly impossible to find the root cause of some runtime errors. Exceptions are integral part of an interface, not an afterthought, i.e they are part of an API design. But most average programmers never think about error handling until the program explodes in their face (or that of the customer). When one thinks about error handling upfront, checked exceptions aren't a problem, they are a very useful tool, and I use them all the time.
Aug 15 2012
prev sibling next sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
I read both articles and while Bruce Eckel's text read a bit like repeated
"swallow exception" to "avoid reams of code" I found the interview insightful.
Both aren't entirely negative on checked exceptions and Hejlsberg actually
wants them:

  [Anders Hejlsberg]: "And so, when you take all of these issues, to me it just
seems more thinking is needed before we put some kind of checked exceptions

knowing what exceptions can get thrown, and having some sort of tool that
checks."

The arguments against the Java model were:

1) The programmer, annoyed by the compiler, swallows exceptions with empty
catch clauses and forgets about them.

I think _if_ the intention is to get back to it later, you can always write "//
TODO: handle the missing icon, by loading a stock icon from the OS". On the
other hand, if you just don't want to declare the thrown exception, then this
is wrong thinking in my opinion. Usually when I am in this situation in Java it
makes me think about the error handling: Can this error be handled gracefully?
If so, right here or should it bubble up? Where is the right level to handle
it? At the end of this process I have the positive feeling that I got the error
handling right.

2) Versioning; a change in a function may add a thrown exception, breaking
client code. Often those clients want to ignore any exceptions (and pass them
on).

Ok, accepted. The client code would have to change its "throws" list for no
perceivable benefit.

3) Declaring the thrown exception doesn't scale well when you call into
multiple subsystems that each throw different exceptions, where you would end
up declaring dozens of thrown exceptions.

I frankly have to say that I never worked on that big projects, that I had to
declare 40 thrown exceptions. And the question may be asked if you should just
wrap the exception into another at that point, because you obviously reached a
granularity at which the finer details of the sub system failures have become
secondary.


So does it all boil down to the potentially long and cascading list of "throws"?
This is not a first grade language issue, I realize that. It's just when you
come across it and find yourself documenting the thrown exceptions in DDoc
where they aren't checked or anything, it cries for a solution. The solution
current languages take seems to be "let the exceptions slip through, more often
than not you don't handle them anyway".
How can we reap all the benefits, but avoid the manual listing of all thrown
exceptions?

-- 
Marco
Aug 11 2012
next sibling parent reply Paulo Pinto <pjmlp progtools.org> writes:
Am 12.08.2012 08:22, schrieb Marco Leise:
 I read both articles and while Bruce Eckel's text read a bit like repeated
"swallow exception" to "avoid reams of code" I found the interview insightful.
Both aren't entirely negative on checked exceptions and Hejlsberg actually
wants them:

    [Anders Hejlsberg]: "And so, when you take all of these issues, to me it
just seems more thinking is needed before we put some kind of checked

tremendous value in knowing what exceptions can get thrown, and having some
sort of tool that checks."

 The arguments against the Java model were:

 1) The programmer, annoyed by the compiler, swallows exceptions with empty
catch clauses and forgets about them.

 I think _if_ the intention is to get back to it later, you can always write
"// TODO: handle the missing icon, by loading a stock icon from the OS". On the
other hand, if you just don't want to declare the thrown exception, then this
is wrong thinking in my opinion. Usually when I am in this situation in Java it
makes me think about the error handling: Can this error be handled gracefully?
If so, right here or should it bubble up? Where is the right level to handle
it? At the end of this process I have the positive feeling that I got the error
handling right.

 2) Versioning; a change in a function may add a thrown exception, breaking
client code. Often those clients want to ignore any exceptions (and pass them
on).

 Ok, accepted. The client code would have to change its "throws" list for no
perceivable benefit.

 3) Declaring the thrown exception doesn't scale well when you call into
multiple subsystems that each throw different exceptions, where you would end
up declaring dozens of thrown exceptions.

 I frankly have to say that I never worked on that big projects, that I had to
declare 40 thrown exceptions. And the question may be asked if you should just
wrap the exception into another at that point, because you obviously reached a
granularity at which the finer details of the sub system failures have become
secondary.


 So does it all boil down to the potentially long and cascading list of
"throws"?
 This is not a first grade language issue, I realize that. It's just when you
come across it and find yourself documenting the thrown exceptions in DDoc
where they aren't checked or anything, it cries for a solution. The solution
current languages take seems to be "let the exceptions slip through, more often
than not you don't handle them anyway".
 How can we reap all the benefits, but avoid the manual listing of all thrown
exceptions?
I have a large experience in JVM and to some extent .NET enterprise projects. These projects have a multi-site component usually in three development sites, scattered around Europe and Asia, having from 30 up to 300 developers on project. To keep costs per team member low, not everyone on the projects is a top coder, many are on their first or second big project. Throws in Java method declarations are reduced to "throws Exception", or "throws RuntimeException" with the real exception being wrapped in a RuntimeException. Many places where the exceptions occur are handled like try { // ... } catch (Exception e) { e.printStackException(); //TODO: fix later (Like you describe) } Sure we try to fight against this type of code, but at the end of the day, there are many other issues to solve, and this type of code gets low priority as fixing it does not make money. Checked exceptions are a failed experiment, and I surely hope that D does not get them. It is a bit like the arguments about manual memory management, sure good coders are able to make proper use of such abstractions, but in real life, projects seldom have real good coders on their teams. And when they have them, there are many other issues to take care of. -- Paulo
Aug 12 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Paulo Pinto:

And when they have them, there are many other issues to take 
care of.<
This is a bad argument because there are always other issues to take care of. Even if a firm buys an artificial intelligence able to self-write all the code, I am sure people in that firm will keep saying "we have many other issues beside writing code!". Bye, bearophile
Aug 12 2012
next sibling parent reply "Paulo Pinto" <pjmlp progtools.org> writes:
On Sunday, 12 August 2012 at 11:48:23 UTC, bearophile wrote:
 Paulo Pinto:

And when they have them, there are many other issues to take 
care of.<
This is a bad argument because there are always other issues to take care of. Even if a firm buys an artificial intelligence able to self-write all the code, I am sure people in that firm will keep saying "we have many other issues beside writing code!". Bye, bearophile
Sure it is, but I've learned that if you live in the Fortune 500 corporation world, it not worth fighting against it. Actually there are a few talks in InfoQ about this type of issue. http://www.infoq.com/presentations/Stop-Refactoring http://www.infoq.com/presentations/Who-Ever-Said-Programs-Were-Supposed-to-be-Pretty -- Paulo
Aug 12 2012
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sun, 12 Aug 2012 14:34:58 +0200
schrieb "Paulo Pinto" <pjmlp progtools.org>:

 On Sunday, 12 August 2012 at 11:48:23 UTC, bearophile wrote:
 Paulo Pinto:

And when they have them, there are many other issues to take 
care of.<
This is a bad argument because there are always other issues to take care of. Even if a firm buys an artificial intelligence able to self-write all the code, I am sure people in that firm will keep saying "we have many other issues beside writing code!". Bye, bearophile
Sure it is, but I've learned that if you live in the Fortune 500 corporation world, it not worth fighting against it. Actually there are a few talks in InfoQ about this type of issue. http://www.infoq.com/presentations/Stop-Refactoring http://www.infoq.com/presentations/Who-Ever-Said-Programs-Were-Supposed-to-be-Pretty -- Paulo
There is code to be written in different areas of business for sure. There is rapid changing business code as yours, there is moderately changing application software, there are extensible tools like Eclipse and it goes further on to libraries and software used in sensitive areas, nuclear power plants, medical or mars robots. So there's definitely people who don't want to be slowed down by unnecessary errors and strictness in the language because it doesn't make money, and others who want to have a look at every little warning to make the code as failsafe as possible. I'm thinking of unhandled exceptions as well as integer overflow and similar. In the end your products wouldn't be finished in time either, if the libraries and tools you build them with weren't good. And open-source software often has the benefit there, that you can actually look at the source if something remains unclear in the documentation, and also that often a lot of people have looked over the code; people with different backgrounds and experience, that detect other types of bugs and pitfalls. In that way success is not always defined economically. It is defined by the goals you set for a given project. A person who uses test driven development might chose D, because of its built in unit tests and invariant() {...}. Similarly a physicist might shy away from it, because of the semantic noise. (They want an integer, but are confronted with the concept of signed/unsigned 32 and 64 bit values and BitInts) TL:DR - it all depends on your target audience :) -- Marco
Aug 12 2012
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/12/2012 4:48 AM, bearophile wrote:
 Paulo Pinto:

 And when they have them, there are many other issues to take care of.<
This is a bad argument because there are always other issues to take care of. Even if a firm buys an artificial intelligence able to self-write all the code, I am sure people in that firm will keep saying "we have many other issues beside writing code!".
Not at all. If you fail to focus on your priorities, you will fail.
Aug 12 2012
prev sibling parent "SomeDude" <lovelydear mailmetrash.com> writes:
On Sunday, 12 August 2012 at 06:22:37 UTC, Marco Leise wrote:
 I read both articles and while Bruce Eckel's text read a bit 
 like repeated "swallow exception" to "avoid reams of code" I 
 found the interview insightful. Both aren't entirely negative 
 on checked exceptions and Hejlsberg actually wants them:

   [Anders Hejlsberg]: "And so, when you take all of these 
 issues, to me it just seems more thinking is needed before we 

 But that said, there's certainly tremendous value in knowing 
 what exceptions can get thrown, and having some sort of tool 
 that checks."

 The arguments against the Java model were:

 1) The programmer, annoyed by the compiler, swallows exceptions 
 with empty catch clauses and forgets about them.

 I think _if_ the intention is to get back to it later, you can 
 always write "// TODO: handle the missing icon, by loading a 
 stock icon from the OS". On the other hand, if you just don't 
 want to declare the thrown exception, then this is wrong 
 thinking in my opinion. Usually when I am in this situation in 
 Java it makes me think about the error handling: Can this error 
 be handled gracefully? If so, right here or should it bubble 
 up? Where is the right level to handle it? At the end of this 
 process I have the positive feeling that I got the error 
 handling right.

 2) Versioning; a change in a function may add a thrown 
 exception, breaking client code. Often those clients want to 
 ignore any exceptions (and pass them on).

 Ok, accepted. The client code would have to change its "throws" 
 list for no perceivable benefit.

 3) Declaring the thrown exception doesn't scale well when you 
 call into multiple subsystems that each throw different 
 exceptions, where you would end up declaring dozens of thrown 
 exceptions.

 I frankly have to say that I never worked on that big projects, 
 that I had to declare 40 thrown exceptions. And the question 
 may be asked if you should just wrap the exception into another 
 at that point, because you obviously reached a granularity at 
 which the finer details of the sub system failures have become 
 secondary.


 So does it all boil down to the potentially long and cascading 
 list of "throws"?
 This is not a first grade language issue, I realize that. It's 
 just when you come across it and find yourself documenting the 
 thrown exceptions in DDoc where they aren't checked or 
 anything, it cries for a solution. The solution current 
 languages take seems to be "let the exceptions slip through, 
 more often than not you don't handle them anyway".
 How can we reap all the benefits, but avoid the manual listing 
 of all thrown exceptions?
My experience and conclusions are very similar to yours. I would simply add that the versioning problem simply is a change of interface. The compiler will force you to add a throws clause to your method signature if your code is likely to throw a new kind of exception (unless you handle it yourself). So you very well know you are making a breaking change, and that you risk infuriating your customers because of this. So I find it to be a fairly weak argument.
Aug 15 2012
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
Perhaps a workable compromise is to make ddoc able to 
automatically output the throws list.

That way, we don't have the hassle of checks, but we do have a 
maintained list at relatively no hassle.


If you call a function to which the source code isn't available, 
ddoc can just point you toward that function's docs. It won't be 
100% complete due to this, but I think it would be decent.
Aug 12 2012
next sibling parent simendsjo <simendsjo gmail.com> writes:
On Sun, 12 Aug 2012 16:33:39 +0200, Adam D. Ruppe  
<destructionator gmail.com> wrote:

 Perhaps a workable compromise is to make ddoc able to automatically  
 output the throws list.

 That way, we don't have the hassle of checks, but we do have a  
 maintained list at relatively no hassle.


 If you call a function to which the source code isn't available, ddoc  
 can just point you toward that function's docs. It won't be 100%  
 complete due to this, but I think it would be decent.
Once we get a lexer, parser and lint tool, undocumented parameters, exceptions etc could be marked as warnings too. Looking into the future here of course :)
Aug 12 2012
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 12, 2012 16:33:39 Adam D. Ruppe wrote:
 Perhaps a workable compromise is to make ddoc able to
 automatically output the throws list.
 
 That way, we don't have the hassle of checks, but we do have a
 maintained list at relatively no hassle.
That's both a good idea and bad idea, because all it's going to be able to list is the exceptions thrown directly in the function. In order to list them all, it would have to go digging through the whole call list (which not only would be expensive, but isn't even necessarily possible if the source isn't fully available), and if any classes are involved, then inheritence could totally mess up the list, since different derived classes could throw different exceptions. So, unless all you care about is what's thrown directly from the function, you'd end up with a very incomplete list. The advantage is that you'd at least have a partial list, but if it gave the impression that it was the whole list, then that would be a problem. Of course, writing it by hand also tends to only list what gets thrown directly (or maybe also what's thrown in the direct helpe functions), so there wouldn't necessarily be much difference. So, it may be close to what would be written by hand. It's definitely true though that it won't be listing all of the thrown exceptions in the general case. - Jonathan M Davis
Aug 12 2012
parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Sun, 12 Aug 2012 22:01:49 +0100, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 On Sunday, August 12, 2012 16:33:39 Adam D. Ruppe wrote:
 Perhaps a workable compromise is to make ddoc able to
 automatically output the throws list.

 That way, we don't have the hassle of checks, but we do have a
 maintained list at relatively no hassle.
That's both a good idea and bad idea, because all it's going to be able to list is the exceptions thrown directly in the function. In order to list them all, it would have to go digging through the whole call list (which not only would be expensive, but isn't even necessarily possible if the source isn't fully available), and if any classes are involved, then inheritence could totally mess up the list, since different derived classes could throw different exceptions. So, unless all you care about is what's thrown directly from the function, you'd end up with a very incomplete list. The advantage is that you'd at least have a partial list, but if it gave the impression that it was the whole list, then that would be a problem. Of course, writing it by hand also tends to only list what gets thrown directly (or maybe also what's thrown in the direct helpe functions), so there wouldn't necessarily be much difference. So, it may be close to what would be written by hand. It's definitely true though that it won't be listing all of the thrown exceptions in the general case.
I wonder if it might be possible to make an intellisense style GUI/IDE tool/plugin which could determine all exceptions thrown either by direct code inspection or ddoc inspection (when source is unavailable) such that it could actually build a complete list. It would need to cache results in order to be anywhere near performant I reckon. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Aug 13 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-08-13 12:31, Regan Heath wrote:

 I wonder if it might be possible to make an intellisense style GUI/IDE
 tool/plugin which could determine all exceptions thrown either by direct
 code inspection or ddoc inspection (when source is unavailable) such
 that it could actually build a complete list. It would need to cache
 results in order to be anywhere near performant I reckon.
I think that would be great and possible, at lest to some extent. There's always problems with unknown subclasses, dynamically loaded code and so on. -- /Jacob Carlborg
Aug 13 2012
prev sibling next sibling parent reply "Nathan M. Swan" <nathanmswan gmail.com> writes:
On Sunday, 12 August 2012 at 03:02:50 UTC, Marco Leise wrote:
 I just got a bit frustrated and wanted to say that I like 
 working with Exceptions in Java a lot more.
I don't. When writing a simple command line program, when there's an error, it usually means the user messed up and I can't recover. I just print the message and terminate. I don't want to have to write "throws Exception" for everything. void main(string[] args) { try { realMain(args); return 0; } catch (Exception e) { stderr.writeln(e.msg); } } The idea sounds nice, but it's annoying in practice. The point of exceptions is to _centralize_ error handling. Being forced to either catch or declare is almost as bad as C-style errno error handling. Perhaps an annotation might be nice, as long as it doesn't force catching: void buggyFunction(string file, int exception) throws(StdioException);
Aug 13 2012
next sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 13 Aug 2012 10:00:31 +0200
schrieb "Nathan M. Swan" <nathanmswan gmail.com>:

 On Sunday, 12 August 2012 at 03:02:50 UTC, Marco Leise wrote:
 I just got a bit frustrated and wanted to say that I like 
 working with Exceptions in Java a lot more.
I don't. When writing a simple command line program, when there's an error, it usually means the user messed up and I can't recover. I just print the message and terminate. I don't want to have to write "throws Exception" for everything.
But now and then you probably write something else than a simple command line program, right?
 The idea sounds nice, but it's annoying in practice. The point of 
 exceptions is to _centralize_ error handling. Being forced to 
 either catch or declare is almost as bad as C-style errno error 
 handling.
Ok, it is annoying. Still exceptions are not just an opaque blob with a stack trace that you catch in your main(). They are more flexible, but it is difficult to efficiently use this flexibility. For example a routine that processes multiple files may continue with the next file on FileNotFoundExceptions, but throw others. A network application may attempt a few times to reconnect in case of a disconnect. That cannot be accomplished by one centralized exception handler. There are also a couple of occasions where a ConvException is better catched and rethrown as a BadServerResponseException (e.g. a number was expected, but something else returned). In particular when writing a library I want to offer proper exceptions, and since they have the bad nature of aborting all your nested function calls, it is important for me to have the thrown exceptions properly declared - a task that the compiler can do better and faster than me. As it stands I might diverge from my old practice and use only one exception type for a library.
 Perhaps an annotation might be nice, as long as it doesn't force 
 catching:
 
 void buggyFunction(string file, int exception) 
  throws(StdioException);
As someone else said, a D lint tool might help with warnings about undocumented thrown exceptions. But personally I want to be "annoyed" to death by the language until I have made it clear what I want to do with the exceptions, even if I just write "catch (ConvException) { /* cannot happen, input is known good */ }". I don't know how many there are who think like me. Your throws proposal for example could be used to tell the compiler that I want Java style checked exceptions for this function and have the compiler check that I listed them all. An empty list would actually be 'nothrow' then. -- Marco
Aug 13 2012
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 13 Aug 2012 10:50:47 +0200
schrieb Marco Leise <Marco.Leise gmx.de>:

 I don't know how many there are who think like me. Your  throws proposal for
example could be used to tell the compiler that I want Java style checked
exceptions for this function and have the compiler check that I listed them
all. An empty list would actually be 'nothrow' then.
It's actually funny if you consider following 2 sentences from http://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html : "Any Exception that can be thrown by a method is part of the method's public programming interface. Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them." So it is the _public_ programming interface, we should be worried about, not forcing "throws"-lists onto every function and method that isn't intended to be called by others, which would neatly work with an optional throws. -- Marco
Aug 13 2012
parent reply Marco Leise <Marco.Leise gmx.de> writes:
I think I should clarify some things up front.

o First of all, to be able to add  throws to a function at any point,
  means that the compiler would internally replace the flag 'isnothrow'
  with a list of thrown exceptions. That is not much different from what
  there is now and would be part of the mangled name as well, if
  acceptable (length restraints), or - since you cannot overload by
  exceptions - part of an extension to the object file.

o nothrow would be equivalent to the empty list  throws() and usable
  interchangeably.

o For protected and public methods of objects and interfaces that are
  not declared as nothrow, the thrown exceptions would inferred as 
   throws(Exception). This has to be done, since an override of these
  methods could introduce any exception type.

o private methods and regular functions are properly inferred with the
  exceptions they actually throw.

o At this point all the functions and methods carry their hidden  throws
  specification around, but it is neither visible in source code, nor is
  there any impact for developers.

o Once someone adds an  throws to a function, the compiler compares it to
  its internal list and complains if it is missing an exception type.
  The explicit list can contain additional exceptions that aren't in the
  compiler inferred list and it can offer more general exceptions, like
  the base type Exception, as a catch-all.

o What happens with object methods that don't declare anything?
  Since they are inferred as  throws(Exception), no narrowing is possible.
  On the other hand, I think this is the only natural way to handle it.

Thoughts ?

-- 
Marco
Aug 13 2012
parent reply "Nathan M. Swan" <nathanmswan gmail.com> writes:
On Monday, 13 August 2012 at 10:02:23 UTC, Marco Leise wrote:
 Thoughts ?
I like this idea - you can use checked exceptions, but you aren't forced. Though I think private and free functions should by default just use throws(Exception). Not using throws is like saying "I don't pay attention to what errors might occur, a new version might be different." NMS
Aug 13 2012
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 13 Aug 2012 20:17:12 +0200
schrieb "Nathan M. Swan" <nathanmswan gmail.com>:

 On Monday, 13 August 2012 at 10:02:23 UTC, Marco Leise wrote:
 Thoughts ?
I like this idea - you can use checked exceptions, but you aren't forced. Though I think private and free functions should by default just use throws(Exception). Not using throws is like saying "I don't pay attention to what errors might occur, a new version might be different." NMS
Ok, that would simplify the concept, but what would you do about templated functions that operate on ranges, like Dimitry presented? I'd rather have the compiler deduce the exceptions to throws() where I passed in a simple int[], than have to deal with throws(Exception). For normal functions it may be feasible. Also all existing code is not annotated, leaving us in the same situation as with other missing attributes in Phobos and people start to complain "I'd like to use throws, but everything is just throws(Exception)" :p -- Marco
Aug 13 2012
prev sibling parent reply "SomeDude" <lovelydear mailmetrash.com> writes:
On Monday, 13 August 2012 at 08:00:33 UTC, Nathan M. Swan wrote:
 On Sunday, 12 August 2012 at 03:02:50 UTC, Marco Leise wrote:
 I just got a bit frustrated and wanted to say that I like 
 working with Exceptions in Java a lot more.
I don't. When writing a simple command line program, when there's an error, it usually means the user messed up and I can't recover. I just print the message and terminate. I don't want to have to write "throws Exception" for everything. void main(string[] args) { try { realMain(args); return 0; } catch (Exception e) { stderr.writeln(e.msg); } } The idea sounds nice, but it's annoying in practice. The point of exceptions is to _centralize_ error handling. Being forced to either catch or declare is almost as bad as C-style errno error handling.
Or you could have told him HOW he messed up. By just throwing an Exception, you are not helpful at all, you are just telling that he is an ass and that he will be punished for that. Or maybe he will curse you thinking that your program doesn't work. Let's say I write a FileParser class which will read a table of doubles in a file. I use a number of methods defined in the JDK like say Double.parse(String) which throws a NumberFormatException("on line" + lineNumber), and catching that exception, I am able to tell the user that one of the numbers on line lineNumber is badly formatted, instead of just telling him that reading the file with 200,000 lines crashed the program. If I catch an IOException as well, I can inform him that the file is unreadable instead (but that the formatting was not yet in cause). But if I catch a FileNotFoundException first (which derives from IOException), I can be more helpful by informing him/her that the filename passed to the program is wrong. These are entirely different classes of errors, so they need to be distinguished if they are to be handled differently, which is not possible with Exception.
 Perhaps an annotation might be nice, as long as it doesn't 
 force catching:

 void buggyFunction(string file, int exception) 
  throws(StdioException);
It's like saying adding typing to the language is nice as long as it's not enforced by the compiler.
Aug 15 2012
next sibling parent reply "Kagamin" <spam here.lot> writes:
On Wednesday, 15 August 2012 at 17:44:14 UTC, SomeDude wrote:
 Or you could have told him HOW he messed up. By just throwing 
 an Exception, you are not helpful at all, you are just telling 
 that he is an ass and that he will be punished for that. Or 
 maybe he will curse you thinking that your program doesn't work.

 Let's say I write a FileParser class  which will read a table 
 of doubles in a file. I use a number of methods defined in the 
 JDK like say Double.parse(String) which throws a 
 NumberFormatException("on line" + lineNumber), and catching 
 that exception, I am able to tell the user that one of the 
 numbers on line lineNumber is badly formatted, instead of just 
 telling him that reading the file with 200,000 lines crashed 
 the program.
How checked exceptions would help you decide whether line number should be included in the error message?
 If I catch an IOException as well, I can inform him that the 
 file is unreadable instead (but that the formatting was not yet 
 in cause). But if I catch a FileNotFoundException first (which 
 derives from IOException), I can be more helpful by informing 
 him/her that the filename passed to the program is wrong.
How checked exceptions would help you design exception hierarchy? What's your point?
Aug 16 2012
parent "SomeDude" <lovelydear mailmetrash.com> writes:
On Thursday, 16 August 2012 at 10:37:01 UTC, Kagamin wrote:
 On Wednesday, 15 August 2012 at 17:44:14 UTC, SomeDude wrote:
 Or you could have told him HOW he messed up. By just throwing 
 an Exception, you are not helpful at all, you are just telling 
 that he is an ass and that he will be punished for that. Or 
 maybe he will curse you thinking that your program doesn't 
 work.

 Let's say I write a FileParser class  which will read a table 
 of doubles in a file. I use a number of methods defined in the 
 JDK like say Double.parse(String) which throws a 
 NumberFormatException("on line" + lineNumber), and catching 
 that exception, I am able to tell the user that one of the 
 numbers on line lineNumber is badly formatted, instead of just 
 telling him that reading the file with 200,000 lines crashed 
 the program.
How checked exceptions would help you decide whether line number should be included in the error message?
You didn't get my point because it was badly formulated. I wanted to emphasize here that because the exception is typed, you can give a better information on what is wrong (here a bad formatting, and you throw in the line number). The interface of Double.parse() *forces* you to catch that exception, and that is a *good* thing. If it didn't force you to catch it, you would lazily 1) not catch and let the program crash 2) catch an Exception and not be able to tell the user what's the root cause of the error, leaving him scratching his head and thinking that your program is actually at fault (because it failed) and not the file. So in a sense, Double.parse(), by throwing a NumberFormatException, forces you to be precise in your error handling and to think about it, i.e answer the questions: a) must I handle the exception or pass it to another level where it makes sense to handle it b) how can I provide the best information as to how to handle the situation. Just placing a catch all Exception at the top level is obviously not enough, because all it says is "something went wrong". It doesn't help handling the error at the right place, in the correct manner. It's a misconception that is all too common in the C++ world because in C++, exceptions are so crippled that they are basically unusable, so people resort to the catch all trick, which is most often less than useless.
 If I catch an IOException as well, I can inform him that the 
 file is unreadable instead (but that the formatting was not 
 yet in cause). But if I catch a FileNotFoundException first 
 (which derives from IOException), I can be more helpful by 
 informing him/her that the filename passed to the program is 
 wrong.
How checked exceptions would help you design exception hierarchy? What's your point?
The exception hierarchy helps choosing the right level of "graininess" in error handling depending on how you want the user to handle errors. You may want to help him establish a diagnosis, in which case you will throw the most discriminating exceptions, or you may just want to inform him that something went wrong, in which case you will rather throw a root exception class. This is very similar to the choice you make when writing logs and choose their log level. Because checked exceptions force you to catch them, you can catch exceptions high in the hierarchy in order to avoid catching every single leaf, which is the case if you are not interested in handling all these different cases.
Aug 17 2012
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Wed, 15 Aug 2012 19:44:13 +0200
schrieb "SomeDude" <lovelydear mailmetrash.com>:

 On Monday, 13 August 2012 at 08:00:33 UTC, Nathan M. Swan wrote:
 Perhaps an annotation might be nice, as long as it doesn't 
 force catching:

 void buggyFunction(string file, int exception) 
  throws(StdioException);
It's like saying adding typing to the language is nice as long as it's not enforced by the compiler.
I am on the same boat, but the number of people who are annoyed by the excrescences is high. That's why I came to the conclusion that both of you should have their way. You can annotate (which means the buggyFunction can only throw StdioException), but you don't need to catch it on the caller side. (Unless you also add an throws or nothrow there.) Also, I want to repeat that throws can be put into DDoc automatically, avoiding the manual documentation and resulting in more modern convenience. -- Marco
Aug 17 2012
prev sibling next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 12-Aug-12 07:02, Marco Leise wrote:
 I just got a bit frustrated and wanted to say that I like working with
Exceptions in Java a lot more.
That has to do first but not foremost with the declaration:
 ---Java->>

 class MyException extends Exception {
    public MyException(String msg) {
      super(msg);
    }
    public MyException(String msg, Throwable next) {
      super(msg, next)
    }
 }

 <<-Java---
I think the true cryptonite that melts "checked exceptions" to a pile of green goo is templated code: So (*yawn*) tell what kind of exception specification the following function should have: auto joiner(RoR, Separator)(RoR r, Separator sep); How would you guarantee upfront what kind of exceptions it can throw is beyond me. It all depends on code that you can't reach or know by the very definition of template. Back to Java: what is I find strange is the lack of sensible tools to do transactional or exception safe code within the language. No RAII objects or just at least any kludge to reliably register cleanup/rollback, only "good" old try/finally. -- Dmitry Olshansky
Aug 13 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/13/2012 05:32 PM, Dmitry Olshansky wrote:
 I think the true cryptonite that melts "checked exceptions" to a pile of
 green goo is templated code:

 So (*yawn*) tell what kind of exception specification the following
 function should have:

 auto joiner(RoR, Separator)(RoR r, Separator sep);

 How would you guarantee upfront what kind of exceptions it can throw is
 beyond me. It all depends on code that you can't reach or know by the
 very definition of template.
Well, presumably the exception specification would be inferred automatically for templates.
Aug 13 2012
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 13-Aug-12 19:50, Timon Gehr wrote:
 On 08/13/2012 05:32 PM, Dmitry Olshansky wrote:
 I think the true cryptonite that melts "checked exceptions" to a pile of
 green goo is templated code:

 So (*yawn*) tell what kind of exception specification the following
 function should have:

 auto joiner(RoR, Separator)(RoR r, Separator sep);

 How would you guarantee upfront what kind of exceptions it can throw is
 beyond me. It all depends on code that you can't reach or know by the
 very definition of template.
Well, presumably the exception specification would be inferred automatically for templates.
What's the propose then? And how end user will get any idea what to put in his function where he uses it? I see one, but it's not pretty - run compiler once - see complaints, add requested types to throws, re-run the compiler? -- Dmitry Olshansky
Aug 13 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/13/2012 05:54 PM, Dmitry Olshansky wrote:
 On 13-Aug-12 19:50, Timon Gehr wrote:
 On 08/13/2012 05:32 PM, Dmitry Olshansky wrote:
 I think the true cryptonite that melts "checked exceptions" to a pile of
 green goo is templated code:

 So (*yawn*) tell what kind of exception specification the following
 function should have:

 auto joiner(RoR, Separator)(RoR r, Separator sep);

 How would you guarantee upfront what kind of exceptions it can throw is
 beyond me. It all depends on code that you can't reach or know by the
 very definition of template.
Well, presumably the exception specification would be inferred automatically for templates.
What's the propose then?
The same as the OT describes. Don't get me wrong, I am certainly no proponent of adding Java-style checked exceptions to D.
 And how end user will get any idea what to put
 in his function where he uses it?
The end user is aware of what the template arguments are.
 I see one, but it's not pretty - run compiler once - see complaints,
 add requested types to throws, re-run the compiler?
Either add requested types to throws or catch and handle the respective exceptions. I assume that this is basically the entire point of statically checked exception specifications.
Aug 13 2012
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 13 Aug 2012 19:54:47 +0400
schrieb Dmitry Olshansky <dmitry.olsh gmail.com>:

 On 13-Aug-12 19:50, Timon Gehr wrote:
 On 08/13/2012 05:32 PM, Dmitry Olshansky wrote:
 I think the true cryptonite that melts "checked exceptions" to a pile of
 green goo is templated code:

 So (*yawn*) tell what kind of exception specification the following
 function should have:

 auto joiner(RoR, Separator)(RoR r, Separator sep);

 How would you guarantee upfront what kind of exceptions it can throw is
 beyond me. It all depends on code that you can't reach or know by the
 very definition of template.
The good thing is whatever your argument is, nothrow inevitably has to suffer from it, too. Really I'd like to label this situation as 'bad', when you don't know what exceptions a function may throw. Then why have different exception types at all?
 Well, presumably the exception specification would be inferred
 automatically for templates.
What's the propose then? And how end user will get any idea what to put in his function where he uses it? I see one, but it's not pretty - run compiler once - see complaints, add requested types to throws, re-run the compiler?
Yes it is that bad(tm) ^^. Ok, who is the end user? If I am the user of someone's library and it has an throws(...) spec, I get an exact idea what to put into my code to handle the exceptions - if I want to. If I'm writing library code on the other hand it depends on the business I'm doing. I'd expect that fast living close to the market code will likely not use this feature, whereas libraries want to be specific about their public API, which includes the exceptions that they throw. I see it as a final step alongside the documentation of a library to add the throws(...), so it doesn't break the workflow much. As for the benefits: o can act as a contract in class hierarchies when used on overrideable methods o allows you to decide at any point to limit the thrown exceptions to a certain set (e.g. handle cases of ConvException or UTFException before the public API) o makes this automatically visible in DDoc (including any comment on the exception) throws(ReadException /** if it is not correct. */); o you don't have to document them manually and keep the DDoc up to date, which is much more time consuming than running the compiler twice o let the compiler work for you o I am a lousy salesman writing walls of text Take a look for example at the socket API. Some methods specify the thrown exceptions, others only hint at them by catching them in examples or don't document them at all. You have to start guessing or digging through the source code to find out which error situations result in what exceptions. The InternetAddress ctor taking a host name looks innocent for example as well as most of the Socket methods. In std.datetime, there is a function TimeZone.getInstalledTZNames() where I wonder if the docs are correct. They say on Windows it throws a DateTimeException when the registry cannot be read, but around the actual registry function call I see no try catch to wrap the thrown exception. std.format is sometimes throwing FormatException, but sometimes Exception on similar cases or an UTFException. -- Marco
Aug 13 2012
prev sibling next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 13 August 2012 at 15:32:45 UTC, Dmitry Olshansky wrote:
 So (*yawn*) tell what kind of exception specification the 
 following function should have:

 auto joiner(RoR, Separator)(RoR r, Separator sep);
auto joiner(RoR, Separator)(RoR r, Separator sep) throws(?);
Aug 14 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Tuesday, 14 August 2012 at 23:13:07 UTC, Mehrdad wrote:
 On Monday, 13 August 2012 at 15:32:45 UTC, Dmitry Olshansky 
 wrote:
 So (*yawn*) tell what kind of exception specification the 
 following function should have:

 auto joiner(RoR, Separator)(RoR r, Separator sep);
auto joiner(RoR, Separator)(RoR r, Separator sep) throws(?);
Or even better: auto joiner(RoR, Separator)(RoR r, Separator sep) throws(auto); That way it's easy enough for the programmer to make the compiler shut up (it's certainly easier than swallowing the exception), while allowing him to write functions that are perfectly transparent toward exceptions, and which would be allowed to throw/catch as they would in any other exception-unchecked language. IMO it would work well in practice.
Aug 14 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Tuesday, 14 August 2012 at 23:21:32 UTC, Mehrdad wrote:
 Or even better:

 auto joiner(RoR, Separator)(RoR r, Separator sep)
 	throws(auto);


 That way it's easy enough for the programmer to make the 
 compiler shut up (it's certainly easier than swallowing the 
 exception), while allowing him to write functions that are 
 perfectly transparent toward exceptions, and which would be 
 allowed to throw/catch as they would in any other 
 exception-unchecked language.


 IMO it would work well in practice.
Caveat perhaps worth mentioning: Indirect calls (function pointers, delegates, virtual methods) would be inferred as throw-all, and would preferably give an informational warning to the user that they may need tighter exception specifications.
Aug 15 2012
prev sibling next sibling parent "Paulo Pinto" <pjmlp progtools.org> writes:
On Monday, 13 August 2012 at 15:32:45 UTC, Dmitry Olshansky wrote:
 Back to Java: what is I find strange is the lack of sensible 
 tools to do transactional or exception safe code within the 
 language. No RAII objects or just at least any kludge to 
 reliably register cleanup/rollback, only "good" old try/finally.
and Python already offer for such cases. For example: try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } -- Paulo
Aug 14 2012
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 13 Aug 2012 19:32:38 +0400
schrieb Dmitry Olshansky <dmitry.olsh gmail.com>:

 I think the true cryptonite that melts "checked exceptions" to a pile of=
=20
 green goo is templated code:
=20
 So (*yawn*) tell what kind of exception specification the following=20
 function should have:
=20
 auto joiner(RoR, Separator)(RoR r, Separator sep);
=20
 How would you guarantee upfront what kind of exceptions it can throw is=20
 beyond me. It all depends on code that you can't reach or know by the=20
 very definition of template.
At first I thought the very definition of template doesn't do much in terms= of nothrow inference, so what. But I made it to easy on myself, so I'll go= into details a bit. When the template is instantiated and it has no throws annotations, it wou= ld infer the thrown exceptions in the fashion nothrow is inferred. If you add nothrow/ throws to a surrounding function that uses this instant= iation, then you get into the situation that you really don't know upfront = what is thrown until you do a test compile. I could blame it on the compile time duck typing, that evades declared thro= wn exceptions. It seems that exceptions just don't work with templates [tha= t call arbitrary functions passed to them through struct/class parameters].= In general it is not possible to reason about the thrown exceptions in tem= plated code, unless everything is marked nothrow or the code is simple, lik= e chains of filter, map, reduce, =E2=80=A6. Currently you cannot use joiner in nothrow functions and I have no idea whi= ch exception you are supposed to catch. This is a whole different topic and for the sake of this proposal I'd like = to go with not documenting these exceptions introduced from the outside, bu= t making them aware to the programmer whenever he/she uses throws on funct= ions using such templates. --=20 Marco
Aug 17 2012
prev sibling parent reply "Manipulator" <volcz kth.se> writes:
I had times when I missed the Java-style Exception handling.

First time I just the D sockets exceptions was thrown during 
runtime. The Library Reference didn't tell my anything about 
exceptions neither did the compiler.
This could've been avoided with documentation stating which 
exceptions can be thrown or if the compiler had warned me about 
it.
I see checked exception handling as mean to remind programmers to 
handle certain errors. This is not done in D.

I've also cursed the Java-style many times. For example:
interface MyInterface {
  public void method throws IOException();
}

class MyClass implements MyInterface {
  public void method throws IOException() {
   //Doesn't need throw IOException!!!!
  }
}

I liked the idea when the compiler is able to warn me about 
unhandled exceptions.
Aug 16 2012
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Thu, 16 Aug 2012 15:11:41 +0200
schrieb "Manipulator" <volcz kth.se>:

 I had times when I missed the Java-style Exception handling.
 
 First time I just the D sockets exceptions was thrown during 
 runtime. The Library Reference didn't tell my anything about 
 exceptions neither did the compiler.
 This could've been avoided with documentation stating which 
 exceptions can be thrown or if the compiler had warned me about 
 it.
 I see checked exception handling as mean to remind programmers to 
 handle certain errors. This is not done in D.
 
 I've also cursed the Java-style many times. For example:
 interface MyInterface {
   public void method throws IOException();
 }
 
 class MyClass implements MyInterface {
   public void method throws IOException() {
    //Doesn't need throw IOException!!!!
   }
 }
 
 I liked the idea when the compiler is able to warn me about 
 unhandled exceptions.
 
I've been thinking shortly about this. Can we narrow down the thrown exceptions? Can an interface declare that it's descendants may throw IOExceptions, but an implementation may practically be nothrow? This could have the special effect that in cases where MyClass is used as the declared type, no exception handling would have to be done, while that would still be the case for MyInterface. If that's possible it would be another small improvement over Java. -- Marco
Aug 17 2012