April 13, 2005
"zwang" <nehzgnaw@gmail.com> wrote in message news:d3i61c$p7r$1@digitaldaemon.com...
> Matthew wrote:
>> [NOTE: GVIM's never had any kind of crash, or any other bug that I've ever used. It's great! (Although I wish I could find out how to get it to remember the last frame size, so I don't have to resize it every time)]
>>
> [snip]
>
> I wrote the following lines in $VIM/_vimrc to set up the window size:
>
> winpos 0 0
> set lines=53
> set columns=166
>
> This is of course not a remember-the-last-frame-size solution, but
> you
> might find it useful.

You're now officialy my best friend. :-)

Many thanks


April 13, 2005
>>But why would it be mandatory to shut down? If the core of the app is able to disable the plugin without shutting down, I'd say that's better (assuming, of course, that internal consistency can be ensured, which it can be in many cases, and can't be in many other cases; if it is not clear whether the app is in a consistent state, I agree shutting down completely is the best thing to do)
> 
> Alas, this is quite wrong and misses the point, although you do hint at it. If the plug-in has violated its design, then any further action performed by it or by any other part of the process is, in principle, indeterminate and in outside the bounds of correct behaviour. (Now, of course it is true that in many cases you can carry on for a while, even a long while, but you run a non-zero risk of ending in a nasty crash.)

Well, what you said also misses the point.. In principle, any action performed by a plug-in (or core) is indeterminate and whatever, it doesn't matter whether it has already produced a CP error or not. I fail to see what the big difference is between

assert(a!==null)

and

if (a is null)
    throw new IllegalArgumentException()

They both prevent the code that follows from running in the case where the supplied parameter is null, so you can't run it with invalid parameters, which is the whole purpose of those two statements.

Why is it so hard for you to admit that it is possible to have CP errors in code that cannot corrupt your app? I mean, if you give a plugin what is basically a read-only view of your data, it shouldn't be able to corrupt it. Sure it can, if it wants to, but that has nothing to do with CP, exceptions, errors or whatever.


> It is only the case when a contract violation has occured, because only that is a signal from the code's designer to the code's user (or rather the runtime) that the plug-in is now invalid.

That's true. However, if I have a plugin that displays tooltips on some objects, I totally don't care if it encountered a CP violation or not, if it works, great, if it doesn't, too bad, no tooltips anymore in this session, I'll restart when I want to. But I really don't see a case for forcing the app, which otherwise works perfectly, to shut down.

I mean, if you don't trust your plugins go ahead and abort. But if you take measures to prevent the plugins from corrupting your data in the first place (like a read-only view), and are able to disable them in runtime, and they're not critical, what's the point?

You act as if code was written like

int thrownCP=0;

void someFunc()
{
   if (thrownCP) {
       // delete all files
       // overwrite all memory, except this function
       // try to launch all US nukes
   } else {
       if (something) {
           thrownCP=1;
           throw new CPError();
       }
       // do normal stuff
   }
}


> So, looking back at your para "If the code of the app is able to disable the plugin without shutting down" applies to Exceptions (and Exhaustions), whereas "if it is not clear whether the app is in a consistent state, I agree shutting down completely is the best thing to do" applies to Errors. These two things hold, of course, since they are the definitions of Exceptions and Errors.

Well, who are you to decide that a CP error means an inconsistent state? Sure, it does in many cases, but not necessarily always. All I'm saying is that one should have a choice.


> CP violations are never tolerated, which means they get fixed _very_ quickly.

Great, I just don't think everybody should be forced to work that way.


>>>>I mean, when I do something like inspect a value in a debugger, and the value is 150MB and the debugger runs out of memory, I don't want it to stop, just because it can't show me a var (which can just as easily manifest as an assertion error or whatever)...
>>>
>>>Out of memory is not an error, it's an exception, so that's just not an issue.
>>
>>Like I said, out of memory can just as well manifest itself later as a broken contract or whatever.
> 
> 
> No, it cannot.

Sure it can:

int[] allocIfYouCan(int size)
{
    try {
        return new int[size];
    } catch (OutOfMemory ignored) {
        return null;
    }
}

void doSomething(int[] arr)
{
   assert(arr!==null);
}

doSomething(allocIfYouCan(10000000));

Obviously, allocIfYouCan() is not a good idea, but it can still happen.


> Dead wrong. Since 'parts' of the application share an address space, a faulty part of an application is the very definition of the whole application being faulty!
> 
> This is a crucial point, and a sine qua non for discussions on this topic.
> 
> [snip]
> 
> But other languages that don't have pointers are just as dead in the water. If you've a comms server written in Java - I know, I know, but let's assumefor pedagogical purposes that you might - and a plug-in violates its contract, then it can still do anything, like kill threads, write out security information to the console, email James Gosling a nasty letter, delete a crucial file, corrupt a database.

Bah, this is just ridiculous. It can kill threads only if it was written to kill threads. If that is the case, no CP will help you. Same goes for everything else. A CP violation doesn't somehow magically transform the code into something that sends out email..


>  [snip]
> So (hopefully) you see that it is impossible to ever state
> (with even practical certainty) that "a faulty part of the
> application should not be taken as if the whole application
> is faulty".

No, I don't.. There are parts and there are parts. You're saying that even the tiniest error (but only if it was specified in a contract) should abort the app, I'm just saying that in some cases it's possible for that to be overreacting.


>>OK, it is obviously desired in some cases, so I agree it should be supported by the language, BUT, none of the built-in exceptions should then be unrecoverable.
> 
> Well again, I get the feeling that you think I've implied that a wide range of things should be unrecoverable. I have not, and perhaps I should say so explicitly now: AFAIK, only contract violations should be Errors (i.e. unrecoverable), since only they are a message from the author(s) of the code to say when it's become invalid. 

How has the code become invalid exactly? The code doesn't change when it violates a contract.

For another example, let's say you have a DB-handling class with an invariant that the connection is always open to the DB (and that is a totally normal invariant). If you reboot the DB server, which is better - to kill all applications that use such class out there, or for them to reconnect?


> Only the author can know. Not the users of the libraries,
> not the users of any programs, not you or me, not even the designer of the language can make that assertion.

Yup, and the author should have the option of using D's CP constructs without making his app die on every single error that happens.


xs0
April 13, 2005
"Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:d3f1nh$rj4$1@digitaldaemon.com...
> I'm looking into the Error/Exception situation in phobos and previous
posts
> by Walter and others generally argued that Exceptions are recoverable and Errors are not. I believe there isn't an application-independent
definition
> ...

Ben,

There is a lot of stuff in this thread, and quite understandly so, as this is a somewhat touchy subject.

What the exact hierarchy should look like (C#, Java, etc.), I don't really care about. I suppose it is the same for the vast majority of people out there: they will use whatever is available, as long as it meets their needs. Below is what I believe an error-handling design should address. I unfortunetaly do not have time to dwelve in each point for very long, but I doubt anyone would disagree with them. (And let me know if you do!)

The error-handling design:
- shall allow recoverability from normal exceptional cases...
... without checking every line for a return code. Any throw-catch design
has this.

- shall allow specifying a common exit procedure wheter an exception occured
or not
A try-catch-finally construct allows this.

- shall allow the ability to programatically analyze exceptions
It is important that the exception-handling code be able to look at the
exception. It should be able to print out an error message, display
something in the logs, send a SNMP alarm, do some correlation, send it
through a socket, etc. Some of this is achieved by simply catching
exceptions of a specific type, and some is not (for instance, the
human-readable error message). This leads to this first axiom:
*Every throwable object in the system should implement a basic interface*
(or derive from a base class).
This must be so for every library, every method, every class in the system.
*Allowing just any objects to be thrown specifically violates this.*

- shall allow all possible exceptional cases to be caught
This is more or less a sub-point of the above. It may be important for
reporting purposes that all possible errors be caught and reported. This can
be allowed with a catch(...) statement, but honestly, after (...) has been
caught, what can you possibly do with it? This is one of the most stupid
'features' of C++. I usually report: "Unkown exception caught". There is
then a 50% chance that I will find the root cause if I am in the lab and 0%
if it hapenned on a customer's system. (More on debugging later.) So, this
comes back to the point above that all exceptions should derive the same
interface/base class with (at least) a method to get a human readable error
message.
Note: some have argued that throwing an object would allow the application
to crash hard. Whereas I am not sure I understand why anyone would want to
do this (they haven't worked with critical systems for sure), not catching
an error (or rethrowing it) will lead to the same result.

- shall allow for checked and unchecked exceptions
Depending where you come from, I guess you can be all for checked
exceptions, or all against it. The truth of the matter is that both are
necessary in given circumstances.
Checked exceptions are exceptions that clients should be *explicitly* made
aware of and should deal with (if only to rethow it ). I know, I know, this
can be abused and lead to a lot of code simply rethrowing exceptions. It is
true that client code often cannot recover if the callee was not able to. No
matter, these exceptions are useful in certain circumstances.
To mitigate abuses, the default "Exception" class should probably be
unchecked (and not the other way around, like was done in Java).
Methods should list (as per their definitions) all checked exceptions they
throw and compilers should enforce that no other checked could be thrown.

- the language/default library shall define most (all) of its exceptions as
unchecked
In other words, it should assume the application logic ensures error-free
operation. For instance, an array list throwing IndexNotFoundExceptions
should not force clients to catch it.

- shall allow exceptions to be cascaded
In some situations, cascading exceptions is the best way to convey what
happened exactly. Also, it allows midware to specify aggregate exceptions
(that could have many causes) and let clients get to the exact root cause if
they so desire (most probably for error reporting). Cascading is usually
done by adding a parameter to the constructor and adding a getter to the
base exception class/interface:
this(..., Exception causedBy = null);
Exception causedBy();

- shall help debugging as much as possible
This is probably the most important point and can't be stressed enough. An
error-handling scheme that allows me to know exactly where the error
occured, by who the function was called (stack trace) and what were the
parameters, even when the error happened only once in the field is an
incredible blessing. It is great being able to tell a customer: "we know
what the problem is and a patch will be ready for you tomorrow". Even when
the root problem is an obscure race condition that never occured in your
gazillion tests in the lab. This saves a lot of people's asses and makes the
programmer's job a lot more enjoyable (and a hell of a lot less stressful
when you work with critical systems). You may think I exagerate, but I
don't... (speaking from experience here). And bugs are a reality in software
development, even in critical systems. No matter how good or witty you are.
More than anything else stack tracing leads to trustable code and rapid
development. Java does this well enough, but I understand that it may not be
possible to extract all the run-time information available to a JVM in
compiled code like D (and C++). However, every efforts should be made toward
that goal. For instance, if it is possible, at a performance cost, to have
stack traces, etc. available in the exception, I believe it should be made
available. In debug mode only perhaps, but I would let the programmer decide
if he still wants that info in production code. Performance is only one
factor in production code, but customers are often a lot more interested in
stability. If having stack traces costs 10% in performance but allows me to
iron out hard to find bugs in a day vs a week (or never), I'd chose the 10%
performance cost every time. Buying hardware 10% faster is cheaper than
paying a programmer (me!) finding hard race-conditions bugs. I am no
compiler writer though, so I don't know exactly what that would entail.

Hoping I am not forgetting anything...


BTW, thanks for all your hard work on D. I can honestly say D is the most exciting thing I have come across in a looonnnngggg time. I spent all (last) weekend checking it out, and I couldn't get to sleep... Went to bed at 5 or 6 AM every morning to the dismay of my SO... I am now tired as hell, but very, very excited. Anyway, I am about to send a few bugs and glitches here and there (and some suggestions perhaps). D has a few rough edges (like exception-handling in fact), but I will program in D in my spare time from now on. Got a project up my sleeve, and I believe I found a language to grace it with!  ;)

Max


April 13, 2005
Hmmm... just glancing over this, I have to wonder.  Is there more than one interpretation of "CP" at work here?  I see some talk of what sounds like contract programming violations, and other talk of what could pass as co-processor errors or code page faults, or what-ever.  Maybe a little clarification is in order... then again, maybe I'm mistaken.

TZ

"xs0" <xs0@xs0.com> wrote in message news:d3itaa$1dtc$1@digitaldaemon.com...
> >>But why would it be mandatory to shut down? If the core of the app is able to disable the plugin without shutting down, I'd say that's better (assuming, of course, that internal consistency can be ensured, which it can be in many cases, and can't be in many other cases; if it is not clear whether the app is in a consistent state, I agree shutting down completely is the best thing to do)
> >
> > Alas, this is quite wrong and misses the point, although you do hint at it. If the plug-in has violated its design, then any further action performed by it or by any other part of the process is, in principle, indeterminate and in outside the bounds of correct behaviour. (Now, of course it is true that in many cases you can carry on for a while, even a long while, but you run a non-zero risk of ending in a nasty crash.)
>
> Well, what you said also misses the point.. In principle, any action performed by a plug-in (or core) is indeterminate and whatever, it doesn't matter whether it has already produced a CP error or not. I fail to see what the big difference is between
>
> assert(a!==null)
>
> and
>
> if (a is null)
>      throw new IllegalArgumentException()
>
> They both prevent the code that follows from running in the case where the supplied parameter is null, so you can't run it with invalid parameters, which is the whole purpose of those two statements.
>
> Why is it so hard for you to admit that it is possible to have CP errors in code that cannot corrupt your app? I mean, if you give a plugin what is basically a read-only view of your data, it shouldn't be able to corrupt it. Sure it can, if it wants to, but that has nothing to do with CP, exceptions, errors or whatever.
>
>
> > It is only
> > the case when a contract violation has occured, because only that is
> > a signal from the code's designer to the code's user (or rather the
> > runtime) that the plug-in is now invalid.
>
> That's true. However, if I have a plugin that displays tooltips on some objects, I totally don't care if it encountered a CP violation or not, if it works, great, if it doesn't, too bad, no tooltips anymore in this session, I'll restart when I want to. But I really don't see a case for forcing the app, which otherwise works perfectly, to shut down.
>
> I mean, if you don't trust your plugins go ahead and abort. But if you take measures to prevent the plugins from corrupting your data in the first place (like a read-only view), and are able to disable them in runtime, and they're not critical, what's the point?
>
> You act as if code was written like
>
> int thrownCP=0;
>
> void someFunc()
> {
>     if (thrownCP) {
>         // delete all files
>         // overwrite all memory, except this function
>         // try to launch all US nukes
>     } else {
>         if (something) {
>             thrownCP=1;
>             throw new CPError();
>         }
>         // do normal stuff
>     }
> }
>
>
> > So, looking back at your para "If the code of the app is able to disable the plugin without shutting down" applies to Exceptions (and Exhaustions), whereas "if it is not clear whether the app is in a consistent state, I agree shutting down completely is the best thing to do" applies to Errors. These two things hold, of course, since they are the definitions of Exceptions and Errors.
>
> Well, who are you to decide that a CP error means an inconsistent state? Sure, it does in many cases, but not necessarily always. All I'm saying is that one should have a choice.
>
*snip*


April 13, 2005
comments inline

"Maxime Larose" <mlarose@broadsoft.com> wrote in message news:d3j3m2$1jsu$1@digitaldaemon.com...
>
> "Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:d3f1nh$rj4$1@digitaldaemon.com...
>> I'm looking into the Error/Exception situation in phobos and previous
> posts
>> by Walter and others generally argued that Exceptions are recoverable and Errors are not. I believe there isn't an application-independent
> definition
>> ...
>
> Ben,
>
> There is a lot of stuff in this thread, and quite understandly so, as this is a somewhat touchy subject.
>
> What the exact hierarchy should look like (C#, Java, etc.), I don't really
> care about. I suppose it is the same for the vast majority of people out
> there: they will use whatever is available, as long as it meets their
> needs.
> Below is what I believe an error-handling design should address. I
> unfortunetaly do not have time to dwelve in each point for very long, but
> I
> doubt anyone would disagree with them. (And let me know if you do!)
>
> The error-handling design:
> - shall allow recoverability from normal exceptional cases...
> ... without checking every line for a return code. Any throw-catch design
> has this.
>
> - shall allow specifying a common exit procedure wheter an exception
> occured
> or not
> A try-catch-finally construct allows this.
>
> - shall allow the ability to programatically analyze exceptions
> It is important that the exception-handling code be able to look at the
> exception. It should be able to print out an error message, display
> something in the logs, send a SNMP alarm, do some correlation, send it
> through a socket, etc. Some of this is achieved by simply catching
> exceptions of a specific type, and some is not (for instance, the
> human-readable error message). This leads to this first axiom:
> *Every throwable object in the system should implement a basic interface*
> (or derive from a base class).
> This must be so for every library, every method, every class in the
> system.
> *Allowing just any objects to be thrown specifically violates this.*

Why does having a base class of Object violate this? It has two useful methods: toString() and print(). To me that's what I would want in an exception base class. It would be nice to have methods for getting or printing a stack trace like Java and .Net but I'm not too worried about that and besides it wouldn't show up in D for a while (if it does show up it can be an interface). Is there something in particular that you'd like to see in the exception tree base class that isn't in Object?

> - shall allow all possible exceptional cases to be caught
> This is more or less a sub-point of the above. It may be important for
> reporting purposes that all possible errors be caught and reported. This
> can
> be allowed with a catch(...) statement, but honestly, after (...) has been
> caught, what can you possibly do with it? This is one of the most stupid
> 'features' of C++. I usually report: "Unkown exception caught". There is
> then a 50% chance that I will find the root cause if I am in the lab and
> 0%
> if it hapenned on a customer's system. (More on debugging later.) So, this
> comes back to the point above that all exceptions should derive the same
> interface/base class with (at least) a method to get a human readable
> error
> message.
> Note: some have argued that throwing an object would allow the application
> to crash hard. Whereas I am not sure I understand why anyone would want to
> do this (they haven't worked with critical systems for sure), not catching
> an error (or rethrowing it) will lead to the same result.

D doesn't have catch(...). Instead one can catch(Object obj) and query obj. Technically the doc says you can catch without supplying a variable and it will catch everything and swallow the exception. Hopefully the compiler will warn if someone does that because that seems like an extreme catch.

> - shall allow for checked and unchecked exceptions
> Depending where you come from, I guess you can be all for checked
> exceptions, or all against it. The truth of the matter is that both are
> necessary in given circumstances.
> Checked exceptions are exceptions that clients should be *explicitly* made
> aware of and should deal with (if only to rethow it ). I know, I know,
> this
> can be abused and lead to a lot of code simply rethrowing exceptions. It
> is
> true that client code often cannot recover if the callee was not able to.
> No
> matter, these exceptions are useful in certain circumstances.
> To mitigate abuses, the default "Exception" class should probably be
> unchecked (and not the other way around, like was done in Java).
> Methods should list (as per their definitions) all checked exceptions they
> throw and compilers should enforce that no other checked could be thrown.

I think there are archived threads about checked/unchecked exceptions. Walter didn't seem very keen on them but that might be because of a problem with Java's approach and maybe you are right that a slightly different approach would make them more attractive to Walter. Do you have a set of checked exceptions in mind?

> - the language/default library shall define most (all) of its exceptions
> as
> unchecked
> In other words, it should assume the application logic ensures error-free
> operation. For instance, an array list throwing IndexNotFoundExceptions
> should not force clients to catch it.

agreed.

> - shall allow exceptions to be cascaded
> In some situations, cascading exceptions is the best way to convey what
> happened exactly. Also, it allows midware to specify aggregate exceptions
> (that could have many causes) and let clients get to the exact root cause
> if
> they so desire (most probably for error reporting). Cascading is usually
> done by adding a parameter to the constructor and adding a getter to the
> base exception class/interface:
> this(..., Exception causedBy = null);
> Exception causedBy();

agreed. There have been recent (and probably achived, too) threads about this kind of thing and using it more often. For example Regan had a nice idea about cascading a SystemError to supply platform-specific error information and I've been looking at the various "foo not supported" exceptions in phobos with an eye towards cascading a NotSupportedException.

> - shall help debugging as much as possible
> This is probably the most important point and can't be stressed enough. An
> error-handling scheme that allows me to know exactly where the error
> occured, by who the function was called (stack trace) and what were the
> parameters, even when the error happened only once in the field is an
> incredible blessing. It is great being able to tell a customer: "we know
> what the problem is and a patch will be ready for you tomorrow". Even when
> the root problem is an obscure race condition that never occured in your
> gazillion tests in the lab. This saves a lot of people's asses and makes
> the
> programmer's job a lot more enjoyable (and a hell of a lot less stressful
> when you work with critical systems). You may think I exagerate, but I
> don't... (speaking from experience here). And bugs are a reality in
> software
> development, even in critical systems. No matter how good or witty you
> are.
> More than anything else stack tracing leads to trustable code and rapid
> development. Java does this well enough, but I understand that it may not
> be
> possible to extract all the run-time information available to a JVM in
> compiled code like D (and C++). However, every efforts should be made
> toward
> that goal. For instance, if it is possible, at a performance cost, to have
> stack traces, etc. available in the exception, I believe it should be made
> available. In debug mode only perhaps, but I would let the programmer
> decide
> if he still wants that info in production code. Performance is only one
> factor in production code, but customers are often a lot more interested
> in
> stability. If having stack traces costs 10% in performance but allows me
> to
> iron out hard to find bugs in a day vs a week (or never), I'd chose the
> 10%
> performance cost every time. Buying hardware 10% faster is cheaper than
> paying a programmer (me!) finding hard race-conditions bugs. I am no
> compiler writer though, so I don't know exactly what that would entail.

Agreed that stack traces are very very useful - especially when a report comes in from the field that is not reproducible. If anyone knows of implementations or knows how to implement a "get the stack trace" function I'm sure it would be appreciated. I'm guessing it is compiler dependent, though. I know something exists since MATLAB does it for its C code and of course Java and .Net do it.

> Hoping I am not forgetting anything...

Thanks for the thoughtful post. Hearing fresh voices is very important.

> BTW, thanks for all your hard work on D. I can honestly say D is the most
> exciting thing I have come across in a looonnnngggg time. I spent all
> (last)
> weekend checking it out, and I couldn't get to sleep... Went to bed at 5
> or
> 6 AM every morning to the dismay of my SO... I am now tired as hell, but
> very, very excited. Anyway, I am about to send a few bugs and glitches
> here
> and there (and some suggestions perhaps). D has a few rough edges (like
> exception-handling in fact), but I will program in D in my spare time from
> now on. Got a project up my sleeve, and I believe I found a language to
> grace it with!  ;)

cool. welcome!


April 13, 2005
Your points about throwing Objects are well noted. I didn't realize that the toString and print functions would solve most of the problems I mentionned. I still believe throwing a specific class (or interface) is better in the case more stuff creeps in (like the stack traces). I mean, that's the whole idea behind specializing (a class) in the first place right? In fact, the main idea behind OO inheritance in general. Why would an Object be throwable, when you can have a specialized Throwable class (or whatever) that offers specialized services (like take a snapshot of the stack trace at construction). IMO, it is better to make these kinds of used-all-over-the-place-and-then-some classes/constructs (exceptions, strings, etc.) thinking well into the future. Obviously, not all future cases can be thought of now. However, if you foresee a possible change and if, all other things being equal, a design better accomodates the change than another, why not use the better accomodating design?

You ask about examples using checked exceptions... Hmmm... I guess you could say that checked exceptions are a very useful part of contract programming. Checked exceptions are useful when the exceptional case is part of the possible operation of a given function, but rare enough that you wouldn't want checking the return result at every call. And/or when the exceptional case completely changes your program flow. That is, you want to *assume* things went a certain way, because they will indeed go that way 99% of the time. However you don't want clients to simply forget to implement that case, because it is a very possible case, one they should deal with. A side benefit is that the code is easier to read/maintain as the human mind works in terms of normal cases vs exceptional cases - even if the exceptional case is "normal" for the program itself.

A contrived example: let's say you have part of a program that parses a file
with an arbitrary number of lines in it. One method parses a single line. It
is possible the line is malformed, but very unlikely. How should you define
that method?
1. You return a value saying if the line was successfully parsed or not.
Welcome back in the old days.
2. You throw an exception. Throwing an unchecked exception gives you no
garantee that the client will deal with the case. This is especially true if
the method is in a library. Good programmers read the docs, true?
The real solution in these cases is throwing a checked exception. Clients
will *have* to act upon it. In our cases, an error message could be
displayed that line n is malformed, and parsing continues/stops/whatever.
You have some assurance that the exception will not be caught three callers
up, said caller having absolutely no idea about what went wrong and having
no choice than to simply display the exception text as is.

Again, these checked exceptions are not for the the D core library nor any default language constructs (at all?). At any rate, unchecked exceptions should be the default. Checked ones are for applications and "higher" libraries, to help code and maintain contracts between components.

Thanks,

Max



"Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:d3j9av$1oso$1@digitaldaemon.com...
> comments inline
>
> "Maxime Larose" <mlarose@broadsoft.com> wrote in message news:d3j3m2$1jsu$1@digitaldaemon.com...
> >
> > "Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:d3f1nh$rj4$1@digitaldaemon.com...
> >> I'm looking into the Error/Exception situation in phobos and previous
> > posts
> >> by Walter and others generally argued that Exceptions are recoverable
and
> >> Errors are not. I believe there isn't an application-independent
> > definition
> >> ...
> >
> > Ben,
> >
> > There is a lot of stuff in this thread, and quite understandly so, as
this
> > is a somewhat touchy subject.
> >
> > What the exact hierarchy should look like (C#, Java, etc.), I don't
really
> > care about. I suppose it is the same for the vast majority of people out
> > there: they will use whatever is available, as long as it meets their
> > needs.
> > Below is what I believe an error-handling design should address. I
> > unfortunetaly do not have time to dwelve in each point for very long,
but
> > I
> > doubt anyone would disagree with them. (And let me know if you do!)
> >
> > The error-handling design:
> > - shall allow recoverability from normal exceptional cases...
> > ... without checking every line for a return code. Any throw-catch
design
> > has this.
> >
> > - shall allow specifying a common exit procedure wheter an exception
> > occured
> > or not
> > A try-catch-finally construct allows this.
> >
> > - shall allow the ability to programatically analyze exceptions
> > It is important that the exception-handling code be able to look at the
> > exception. It should be able to print out an error message, display
> > something in the logs, send a SNMP alarm, do some correlation, send it
> > through a socket, etc. Some of this is achieved by simply catching
> > exceptions of a specific type, and some is not (for instance, the
> > human-readable error message). This leads to this first axiom:
> > *Every throwable object in the system should implement a basic
interface*
> > (or derive from a base class).
> > This must be so for every library, every method, every class in the
> > system.
> > *Allowing just any objects to be thrown specifically violates this.*
>
> Why does having a base class of Object violate this? It has two useful methods: toString() and print(). To me that's what I would want in an exception base class. It would be nice to have methods for getting or printing a stack trace like Java and .Net but I'm not too worried about
that
> and besides it wouldn't show up in D for a while (if it does show up it
can
> be an interface). Is there something in particular that you'd like to see
in
> the exception tree base class that isn't in Object?
>
> > - shall allow all possible exceptional cases to be caught
> > This is more or less a sub-point of the above. It may be important for
> > reporting purposes that all possible errors be caught and reported. This
> > can
> > be allowed with a catch(...) statement, but honestly, after (...) has
been
> > caught, what can you possibly do with it? This is one of the most stupid
> > 'features' of C++. I usually report: "Unkown exception caught". There is
> > then a 50% chance that I will find the root cause if I am in the lab and
> > 0%
> > if it hapenned on a customer's system. (More on debugging later.) So,
this
> > comes back to the point above that all exceptions should derive the same
> > interface/base class with (at least) a method to get a human readable
> > error
> > message.
> > Note: some have argued that throwing an object would allow the
application
> > to crash hard. Whereas I am not sure I understand why anyone would want
to
> > do this (they haven't worked with critical systems for sure), not
catching
> > an error (or rethrowing it) will lead to the same result.
>
> D doesn't have catch(...). Instead one can catch(Object obj) and query
obj.
> Technically the doc says you can catch without supplying a variable and it will catch everything and swallow the exception. Hopefully the compiler
will
> warn if someone does that because that seems like an extreme catch.
>
> > - shall allow for checked and unchecked exceptions
> > Depending where you come from, I guess you can be all for checked
> > exceptions, or all against it. The truth of the matter is that both are
> > necessary in given circumstances.
> > Checked exceptions are exceptions that clients should be *explicitly*
made
> > aware of and should deal with (if only to rethow it ). I know, I know,
> > this
> > can be abused and lead to a lot of code simply rethrowing exceptions. It
> > is
> > true that client code often cannot recover if the callee was not able
to.
> > No
> > matter, these exceptions are useful in certain circumstances.
> > To mitigate abuses, the default "Exception" class should probably be
> > unchecked (and not the other way around, like was done in Java).
> > Methods should list (as per their definitions) all checked exceptions
they
> > throw and compilers should enforce that no other checked could be
thrown.
>
> I think there are archived threads about checked/unchecked exceptions. Walter didn't seem very keen on them but that might be because of a
problem
> with Java's approach and maybe you are right that a slightly different approach would make them more attractive to Walter. Do you have a set of checked exceptions in mind?
>
> > - the language/default library shall define most (all) of its exceptions
> > as
> > unchecked
> > In other words, it should assume the application logic ensures
error-free
> > operation. For instance, an array list throwing IndexNotFoundExceptions should not force clients to catch it.
>
> agreed.
>
> > - shall allow exceptions to be cascaded
> > In some situations, cascading exceptions is the best way to convey what
> > happened exactly. Also, it allows midware to specify aggregate
exceptions
> > (that could have many causes) and let clients get to the exact root
cause
> > if
> > they so desire (most probably for error reporting). Cascading is usually
> > done by adding a parameter to the constructor and adding a getter to the
> > base exception class/interface:
> > this(..., Exception causedBy = null);
> > Exception causedBy();
>
> agreed. There have been recent (and probably achived, too) threads about this kind of thing and using it more often. For example Regan had a nice idea about cascading a SystemError to supply platform-specific error information and I've been looking at the various "foo not supported" exceptions in phobos with an eye towards cascading a
NotSupportedException.
>
> > - shall help debugging as much as possible
> > This is probably the most important point and can't be stressed enough.
An
> > error-handling scheme that allows me to know exactly where the error occured, by who the function was called (stack trace) and what were the parameters, even when the error happened only once in the field is an incredible blessing. It is great being able to tell a customer: "we know what the problem is and a patch will be ready for you tomorrow". Even
when
> > the root problem is an obscure race condition that never occured in your
> > gazillion tests in the lab. This saves a lot of people's asses and makes
> > the
> > programmer's job a lot more enjoyable (and a hell of a lot less
stressful
> > when you work with critical systems). You may think I exagerate, but I
> > don't... (speaking from experience here). And bugs are a reality in
> > software
> > development, even in critical systems. No matter how good or witty you
> > are.
> > More than anything else stack tracing leads to trustable code and rapid
> > development. Java does this well enough, but I understand that it may
not
> > be
> > possible to extract all the run-time information available to a JVM in
> > compiled code like D (and C++). However, every efforts should be made
> > toward
> > that goal. For instance, if it is possible, at a performance cost, to
have
> > stack traces, etc. available in the exception, I believe it should be
made
> > available. In debug mode only perhaps, but I would let the programmer
> > decide
> > if he still wants that info in production code. Performance is only one
> > factor in production code, but customers are often a lot more interested
> > in
> > stability. If having stack traces costs 10% in performance but allows me
> > to
> > iron out hard to find bugs in a day vs a week (or never), I'd chose the
> > 10%
> > performance cost every time. Buying hardware 10% faster is cheaper than
> > paying a programmer (me!) finding hard race-conditions bugs. I am no
> > compiler writer though, so I don't know exactly what that would entail.
>
> Agreed that stack traces are very very useful - especially when a report comes in from the field that is not reproducible. If anyone knows of implementations or knows how to implement a "get the stack trace" function I'm sure it would be appreciated. I'm guessing it is compiler dependent, though. I know something exists since MATLAB does it for its C code and of course Java and .Net do it.
>
> > Hoping I am not forgetting anything...
>
> Thanks for the thoughtful post. Hearing fresh voices is very important.
>
> > BTW, thanks for all your hard work on D. I can honestly say D is the
most
> > exciting thing I have come across in a looonnnngggg time. I spent all
> > (last)
> > weekend checking it out, and I couldn't get to sleep... Went to bed at 5
> > or
> > 6 AM every morning to the dismay of my SO... I am now tired as hell, but
> > very, very excited. Anyway, I am about to send a few bugs and glitches
> > here
> > and there (and some suggestions perhaps). D has a few rough edges (like
> > exception-handling in fact), but I will program in D in my spare time
from
> > now on. Got a project up my sleeve, and I believe I found a language to grace it with!  ;)
>
> cool. welcome!
>
>


April 13, 2005
In article <d3i4nm$o0r$1@digitaldaemon.com>, Matthew says...
>
>> One important point is that I'm not recommending the removal of the CP  violation, quite the opposite, but, I believe that the programmer should  be able to make the informed decision about whether it's terminal or not.
>
>Ok. My understanding of your position is that that decision is rightly within the purview of the programmer of a component's client code, whereas I'm saying that (at least in principle) it can only be within the purview of the component's programmer.

At the risk of muddying the waters a bit.  I think one might reasonably argue that violation of preconditions is recoverable while violation of postconditions is not.  In the first case, the client could theoretically detect the error, fix the parameters and call the function again, while in the second case the client has been stuck in a bad application state and there's little he can do about it. Might it make sense to separate these concerns rather than just throwing AssertErrors in all cases?


Sean


April 13, 2005
In article <d3i5dn$oda$1@digitaldaemon.com>, Ben Hinkle says...
>
>Forcing shutdown is annoying. As long as you tell the user what happened and how serious it could be who are we to quit their app? (though honestly I hope we don't start this whole thread over again) In some sense for the user it's like when Windows tells you at some point you have to reboot after an install (well... not all installs but you know what I mean). Windows doesn't pop up a dialog that says "Reboot?" that just has an OK button. Error recovery should inform the user but let them decide what to do - or worst case let the application developer decide.

The only instance where this seems reasonable to me is in kernel code, and in that case I expect the programmer would avoid the use of asserts (in release mode) if he wants to insure the code never halts.  In other cases my personal preference is to terminate the application and use a process monitor to restart it if necessary.


Sean


April 13, 2005
In article <d3j9av$1oso$1@digitaldaemon.com>, Ben Hinkle says...
>
>comments inline
>
>"Maxime Larose" <mlarose@broadsoft.com> wrote in message news:d3j3m2$1jsu$1@digitaldaemon.com...
>>
>> - shall allow the ability to programatically analyze exceptions
>> It is important that the exception-handling code be able to look at the
>> exception. It should be able to print out an error message, display
>> something in the logs, send a SNMP alarm, do some correlation, send it
>> through a socket, etc. Some of this is achieved by simply catching
>> exceptions of a specific type, and some is not (for instance, the
>> human-readable error message). This leads to this first axiom:
>> *Every throwable object in the system should implement a basic interface*
>> (or derive from a base class).
>> This must be so for every library, every method, every class in the
>> system.
>> *Allowing just any objects to be thrown specifically violates this.*
>
>Why does having a base class of Object violate this? It has two useful methods: toString() and print(). To me that's what I would want in an exception base class. It would be nice to have methods for getting or printing a stack trace like Java and .Net but I'm not too worried about that and besides it wouldn't show up in D for a while (if it does show up it can be an interface). Is there something in particular that you'd like to see in the exception tree base class that isn't in Object?

I think the Object base class violates this to some people because it violates the "what the hell is this?" principle (which I just made up).  If an application throws something that is not an exception (ie. that doesn't describe itself in some way) then the client has no idea what the error was.  Sure I could throw a ClientAccount, but what was the error that caused the problem in the first place?  Printing the ClientAccount won't help anyone in determining that.  It would make much more sense to wrap it in an Exception with a bit of descriptive information.


Sean


April 13, 2005
In article <d3jd4b$1sb6$1@digitaldaemon.com>, Sean Kelly says...
>
>At the risk of muddying the waters a bit.  I think one might reasonably argue that violation of preconditions is recoverable while violation of postconditions is not.  In the first case, the client could theoretically detect the error, fix the parameters and call the function again, while in the second case the client has been stuck in a bad application state and there's little he can do about it. Might it make sense to separate these concerns rather than just throwing AssertErrors in all cases?

This has me wondering (and I'm posting this to remind myself to test it), if an exception is thrown out of a public class method with a postcondition, is that postcondition evaluated?  What if the postcondition has an assertion failure as well?  Also, is the class invariant evaluated if an exception is thrown?  What if that also has an assert failure?  I know that auto classes are not currently handled properly if execution leaves scope because of a thrown exception, what about these other cases where we could theoretically have two or more exceptions in flight at the same time?

Note that I'm ignoring finally blocks as exceptions thrown there are ignored and just cause them to complete early (this is an issue in itself and one might argue that finally blocks could violate application integrity depending on what's in them).


Sean