August 17, 2012
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

August 17, 2012
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
August 17, 2012
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 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.

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 would infer the thrown exceptions in the fashion nothrow is inferred.
If you add nothrow/@throws to a surrounding function that uses this instantiation, 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 thrown exceptions. It seems that exceptions just don't work with templates [that call arbitrary functions passed to them through struct/class parameters]. In general it is not possible to reason about the thrown exceptions in templated code, unless everything is marked nothrow or the code is simple, like chains of filter, map, reduce, ….
Currently you cannot use joiner in nothrow functions and I have no idea which 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, but making them aware to the programmer whenever he/she uses @throws on functions using such templates.

-- 
Marco

August 17, 2012
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. 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?

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.) 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. I think WebDAV is one such extension of HTTP.

-- 
Marco

August 17, 2012
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
August 18, 2012
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.
August 19, 2012
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.

August 19, 2012
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
Next ›   Last »
1 2 3 4 5
Top | Discussion index | About this forum | D home