Re: Exception/Error division in D

2012-06-04 Thread Don Clugston

On 01/06/12 22:35, Walter Bright wrote:

On 6/1/2012 11:14 AM, deadalnix wrote:

We are talking about runing scope statement and finally when unwiding
the stack,
not trying to continue the execution of the program.


Which will be running arbitrary code not anticipated by the assert
failure, and code that is highly unlikely to be desirable for shutdown.


Sorry, Walter, that's complete bollocks.

try {
   assert(x == 2);
} catch(AssertException e)
{
   foo();   
}

is exactly equivalent to:

version (release)
{}
else
{
   if (x!=2) foo();
}

Bad practice, sure. But it's not running arbitrary, unanticipated code.



Re: Exception/Error division in D

2012-06-03 Thread deadalnix

Le 01/06/2012 22:35, Walter Bright a écrit :

On 6/1/2012 11:14 AM, deadalnix wrote:

We are talking about runing scope statement and finally when unwiding
the stack,
not trying to continue the execution of the program.


Which will be running arbitrary code not anticipated by the assert
failure, and code that is highly unlikely to be desirable for shutdown.


This is, most of the time, the point of error/exceptions. You rarely
recover
from them in real life.


I believe this is a misunderstanding of what exceptions are for. File
not found exceptions, and other errors detected in inputs, are routine
and routinely recoverable.

This discussion has come up repeatedly in the last 30 years. It's root
is always the same - conflating handling of input errors, and handling
of bugs in the logic of the program.

The two are COMPLETELY different and dealing with them follow completely
different philosophies, goals, and strategies.

Input errors are not bugs, and vice versa. There is no overlap.


I'm pretty sure I understand what you are saying here. We have in fact 3 
cases :

1/ A problem during the execution of an operation (Exceptions).
2/ A logical invalid state in the program (Errors).
3/ The program environment is broken (Error too ATM).

Case 1/ is out of the current discussion scope. In case 3/, it doesn't 
even make sense to throw an Error as we do know, because it isn't even 
sure that this is possible (stack corrupted), or that the information 
provided are correct.


This leave the case 2/ on the table.

Programs are usually an aggregate of several smaller component that 
interacts with each others. Let say, as this is a very common case, I 
have a program that have a network component and another that perform 
some calculations.


If an assert fails in the component that does calculations, it indicate 
a malfunction here. Whatever I do in that module, it is likely that it 
will make no sense. However, unless I consider I may be in case 3/ (but 
then, it isn't even a good response to throw an Error, so we consider we 
aren't) I'm sure that the network module is still in good shape and can 
close the connection.


Re: Exception/Error division in D

2012-06-01 Thread Jens Mueller
Walter Bright wrote:
 On 5/31/2012 1:05 PM, Jens Mueller wrote:
 Okay, let's assume I have separate processes maybe even processes on
 different machines. In one process I get an error. Let's say I want to
 trigger the other process that it restarts the process or just logs the
 event whatever makes sense.
 How do I do this if it not guaranteed that finally/scope blocks are
 being executed?
 
 
 Presumably the operating system provides a means to tell when a
 process is no longer running as part of its inter-process
 communication api.

My point is that you may want to access some state of your invalid
program. State that is lost otherwise. But maybe just having the core
dump is actually enough, i.e. there is no other interesting state. You
are probably right that you can always recover from the error when a new
process is started. At least I cannot can up with a convincing case.

Since the current implementation does not follow the specification
regarding scope and finally block being executed in case of Error will
try ... catch (...Error) keep working? I have code that uses
assertThrows!AssertError to test some in contracts. Will this code
break?

Jens


Re: Exception/Error division in D

2012-06-01 Thread Walter Bright

On 6/1/2012 1:15 AM, Jens Mueller wrote:

Since the current implementation does not follow the specification
regarding scope and finally block being executed in case of Error will
try ... catch (...Error) keep working?


No. The reason for this is the implementation was not updated after the split 
between Error and Exception happened. It was overlooked.



I have code that uses
assertThrows!AssertError to test some in contracts. Will this code
break?


I don't know exactly what your code is, but if you're relying on scope to unwind 
in the presence of Errors, that will break.




Re: Exception/Error division in D

2012-06-01 Thread deadalnix

Le 31/05/2012 21:47, Walter Bright a écrit :

On 5/31/2012 12:40 AM, Jens Mueller wrote:

How do I do a graceful shutdown if finally and scope is not guaranteed
to be executed? Assuming onAssertError, etc. is of no use because I need
to perform different shutdowns due to having different cases or if I
defined my own Error, let's say for some device.


There's no way to guarantee a graceful shutdown.

No way.

If you must have such, then the way to do it is to divide your
application into separate processes that communicate via interprocess
communication, then when one component fails the rest of your app can
restart it or do what's necessary, as the rest is not in an invalid state.



They're is no way to ensure that an IP packet will go throw the 
internet. Let just shutdown that silly thing that internet is right now.


Re: Exception/Error division in D

2012-06-01 Thread deadalnix

Le 01/06/2012 12:29, Walter Bright a écrit :

On 6/1/2012 1:15 AM, Jens Mueller wrote:

Since the current implementation does not follow the specification
regarding scope and finally block being executed in case of Error will
try ... catch (...Error) keep working?


No. The reason for this is the implementation was not updated after the
split between Error and Exception happened. It was overlooked.


I have code that uses
assertThrows!AssertError to test some in contracts. Will this code
break?


I don't know exactly what your code is, but if you're relying on scope
to unwind in the presence of Errors, that will break.



If you have an error, it is already broken in some way.

But this is unreasonable to think that the whole program is broken, 
except in very specific cases (stack corruption for instance) but in 
such a case, you can't throw an error anyway.


Re: Exception/Error division in D

2012-06-01 Thread Tobias Pankrath

On Friday, 1 June 2012 at 12:03:15 UTC, deadalnix wrote:

Le 01/06/2012 12:29, Walter Bright a écrit :

On 6/1/2012 1:15 AM, Jens Mueller wrote:
Since the current implementation does not follow the 
specification
regarding scope and finally block being executed in case of 
Error will

try ... catch (...Error) keep working?


No. The reason for this is the implementation was not updated 
after the

split between Error and Exception happened. It was overlooked.


I have code that uses
assertThrows!AssertError to test some in contracts. Will this 
code

break?


I don't know exactly what your code is, but if you're relying 
on scope

to unwind in the presence of Errors, that will break.



If you have an error, it is already broken in some way.

But this is unreasonable to think that the whole program is 
broken, except in very specific cases (stack corruption for 
instance) but in such a case, you can't throw an error anyway.


I agree. It should be possible to have an plugin system where not 
every null pointer dereference in a plugin screws up the hole 
program. Without using different processes for the plugin.


90% of null pointer dereferences are simple bugs not memory 
corruption.




Re: Exception/Error division in D

2012-06-01 Thread Andrej Mitrovic
On 6/1/12, Tobias Pankrath tob...@pankrath.net wrote:
 I agree. It should be possible to have an plugin system where not
 every null pointer dereference in a plugin screws up the hole
 program. Without using different processes for the plugin.

It should also be possible to correctly release hardware handles
regardless of what happened to the app itself. I hate it when apps
lock up and can't be killed (e.g. ones using ASIO hardware).


Re: Exception/Error division in D

2012-06-01 Thread Jouko Koski

deadalnix deadal...@gmail.com wrote:

Le 31/05/2012 04:10, Walter Bright a écrit :

The correct response to a server app crashing is to restart it, not
attempt to keep a program in an invalid state running.


Should I mention to restart it AFTER A GRACEFUL SHUTDOWN ?


No. Abort with crash dump is good way to do controlled shutdown. If there is 
need for a cleanup, it is better to do it in the upcoming startup where the 
program state is valid. 



Re: Exception/Error division in D

2012-06-01 Thread deadalnix

Le 01/06/2012 02:57, Walter Bright a écrit :

On 5/31/2012 2:23 AM, Lars T. Kyllingstad wrote:

On Thursday, 31 May 2012 at 02:18:22 UTC, Walter Bright wrote:

A recoverable exception is NOT a logic bug in your program, which is
why it is
recoverable.

If there is recovery possible from a particular assert error, then
you are
using asserts incorrectly.


I think this is a key point. Asserts are there to verify and debug
program
logic, they are not part of the logic itself. They are a useful tool
for the
programmer, nothing more. Specifically, asserts are NOT an error handling
mechanism!


Right. And I'd like to amplify that the asserts are also there to detect
program faults hopefully before damage is done.

If a program must continue even after it has failed, then you have a
WRONGLY designed system.

It is extremely important to understand this point if you are
implementing any sort of critical software.


We are talking about runing scope statement and finally when unwiding 
the stack, not trying to continue the execution of the program.


This is, most of the time, the point of error/exceptions. You rarely 
recover from them in real life.


Re: Exception/Error division in D

2012-06-01 Thread deadalnix

Le 01/06/2012 14:16, Tobias Pankrath a écrit :

On Friday, 1 June 2012 at 12:03:15 UTC, deadalnix wrote:

Le 01/06/2012 12:29, Walter Bright a écrit :

On 6/1/2012 1:15 AM, Jens Mueller wrote:

Since the current implementation does not follow the specification
regarding scope and finally block being executed in case of Error will
try ... catch (...Error) keep working?


No. The reason for this is the implementation was not updated after the
split between Error and Exception happened. It was overlooked.


I have code that uses
assertThrows!AssertError to test some in contracts. Will this code
break?


I don't know exactly what your code is, but if you're relying on scope
to unwind in the presence of Errors, that will break.



If you have an error, it is already broken in some way.

But this is unreasonable to think that the whole program is broken,
except in very specific cases (stack corruption for instance) but in
such a case, you can't throw an error anyway.


I agree. It should be possible to have an plugin system where not every
null pointer dereference in a plugin screws up the hole program. Without
using different processes for the plugin.

90% of null pointer dereferences are simple bugs not memory corruption.



You want to crash an airplane or what ???


Re: Exception/Error division in D

2012-06-01 Thread Jonathan M Davis
On Friday, June 01, 2012 03:29:17 Walter Bright wrote:
 On 6/1/2012 1:15 AM, Jens Mueller wrote:
  Since the current implementation does not follow the specification
  regarding scope and finally block being executed in case of Error will
  try ... catch (...Error) keep working?
 
 No. The reason for this is the implementation was not updated after the
 split between Error and Exception happened. It was overlooked.
 
  I have code that uses
  assertThrows!AssertError to test some in contracts. Will this code
  break?
 
 I don't know exactly what your code is, but if you're relying on scope to
 unwind in the presence of Errors, that will break.

std.exception.assertThrown will catch AssertErrors just fine, though I thought 
that it had a warning about catching non-Exceptions, and glancing at it now, 
it doesn't look like it does. I should probably add that. In any case, it's 
specifically designed so that it can catch AssertErrors, and nothing it itself 
does should require cleanup, but if the expression evaluated would have 
required cleanup, and the AssertError skipped it, then whatever program state 
is affected by that is now invalid. Anyone using assertThrown!AssertError is 
going to have to worry about that just as much as when you catch an Error 
yourself. However, it _is_ true that that's safer right now then it would be 
if scope statements, destructors, and finally blocks were no longer run for 
Errors, since in many, many cases, failed assertions in unit tests wouldn't 
really invalidate anything in the program. What's more likely to happen is 
that files won't get cleaned up and stuff ilke that. But the AssertError in 
unit 
tests case is really the only case that I'm aware of where I see a strong 
argument for having cleanup occur for Errors.

- Jonathan M Davis


Re: Exception/Error division in D

2012-06-01 Thread Jonathan M Davis
On Friday, June 01, 2012 14:16:48 Tobias Pankrath wrote:
 90% of null pointer dereferences are simple bugs not memory
 corruption.

True, but it means that you have a logic bug, which means that your program is 
in an invalid state anyway, and continuing could do who-knows-what. If you 
want to handle dereferencing null pointers, then simply check the pointer 
before dereferencing it.

And even if 90% of null pointer dereferences are simple bugs and not memory 
corruption, the program has _no_ way of knowing which it's dealing with, so it 
must assume the worst case scenario.

- Jonathan M Davis


Re: Exception/Error division in D

2012-06-01 Thread Jonathan M Davis
On Friday, June 01, 2012 20:14:45 deadalnix wrote:
 We are talking about runing scope statement and finally when unwiding
 the stack, not trying to continue the execution of the program.

Except that that _is_ continuing execution. It's only running cleanup code, 
but if the program state is invalid, it can't assume that it's any safer to 
run that code than the code following whatever caused the Error.

And if you _really_ need that cleanup code to run, then you need to find other 
ways to make sure that it happens anyway (either that or you need to find a way 
to make it so that it doesn't need to happen), because your program could be 
killed for external reasons outside of your control.

- Jonathan M Davis


Re: Exception/Error division in D

2012-06-01 Thread Walter Bright

On 6/1/2012 11:14 AM, deadalnix wrote:

We are talking about runing scope statement and finally when unwiding the stack,
not trying to continue the execution of the program.


Which will be running arbitrary code not anticipated by the assert failure, and 
code that is highly unlikely to be desirable for shutdown.



This is, most of the time, the point of error/exceptions. You rarely recover
from them in real life.


I believe this is a misunderstanding of what exceptions are for. File not 
found exceptions, and other errors detected in inputs, are routine and 
routinely recoverable.


This discussion has come up repeatedly in the last 30 years. It's root is always 
the same - conflating handling of input errors, and handling of bugs in the 
logic of the program.


The two are COMPLETELY different and dealing with them follow completely 
different philosophies, goals, and strategies.


Input errors are not bugs, and vice versa. There is no overlap.


Re: Exception/Error division in D

2012-05-31 Thread Jacob Carlborg

On 2012-05-30 23:16, Jonathan M Davis wrote:


You can catch them to print out additional information or whatever is useful
to generate more information about the Error. In fact, just what the Error
gives you is already more useful: message, file, line number, stack trace, etc.
That alone makes an Error more useful than a halt instruction.


If I recall correctly you has been arguing that Errors shouldn't be 
catchable, as they are today, and this needed to be fixed. Hmm, or was 
that Steven.



You can catch them to attempt explicit cleanup that absolutely must be done
for whatever reason (with the knowledge that it's potentially dangerous to do
that cleanup due to the Error).

You can catch them in very controlled circumstances where you know that
continuing is safe (obviously this isn't the sort of thing that you do in
@safe code). For instance, in some restricted cases, that could be done with
an OutOfMemoryError. But when you do that sort of thing you have to catch the
Error _very_ close to the throw point and be sure that there's no cleanup code
in between. It only works when you can guarantee yourself that the program
state is not being compromised by the Error, and you're able to guarantee that
continuing from the catch point is safe. That works in some cases with
AssertError in unit test code but becomes problematic as such code becomes
more complex.


I'm mostly interested in letting the user know something went wrong and 
then exit the application.


--
/Jacob Carlborg


Re: Exception/Error division in D

2012-05-31 Thread Jonathan M Davis
On Thursday, May 31, 2012 08:26:18 Jacob Carlborg wrote:
 On 2012-05-30 23:16, Jonathan M Davis wrote:
  You can catch them to print out additional information or whatever is
  useful to generate more information about the Error. In fact, just what
  the Error gives you is already more useful: message, file, line number,
  stack trace, etc. That alone makes an Error more useful than a halt
  instruction.
 
 If I recall correctly you has been arguing that Errors shouldn't be
 catchable, as they are today, and this needed to be fixed. Hmm, or was
 that Steven.

No. I haven't been arguing that. It's not particularly safe to catch Errors, 
but they're catchable on purpose. It's catching and _handling_ an Error that's 
generally a bad idea - that and continuing to execute after catching the Error 
rather than letting the program terminate. It may be appropriate in very rare 
examples where the programmer knows what they're doing, but in general, 
catching them to do much beyond print out additional information or maybe do 
some absolutely critical cleanup is a bad idea.

The real question is whether any cleanup should be attempted on Error (i.e. 
destructors, scope statements, and finally blocks). Running that code is risky 
when an Error occurs, because the program is in an invalid state. It's 
possible that running it could actually do damage of some variety, depending 
on the state of the program and what the cleanup does. But skipping all of 
that cleanup can be a problem too, since that cleanup generally needs to be 
done. Depending on what the Error was, the cleanup may actually work and 
therefore leave the program in a less invalid state. So, it's a question of 
whether attempting cleanup in an invalid state or skipping cleanup in an 
invalid state is riskier. Per Walter, there's no guarantee that that cleanup 
will occur, but with the current implementation it almost always does.

  You can catch them to attempt explicit cleanup that absolutely must be
  done
  for whatever reason (with the knowledge that it's potentially dangerous to
  do that cleanup due to the Error).
  
  You can catch them in very controlled circumstances where you know that
  continuing is safe (obviously this isn't the sort of thing that you do in
  @safe code). For instance, in some restricted cases, that could be done
  with an OutOfMemoryError. But when you do that sort of thing you have to
  catch the Error _very_ close to the throw point and be sure that there's
  no cleanup code in between. It only works when you can guarantee yourself
  that the program state is not being compromised by the Error, and you're
  able to guarantee that continuing from the catch point is safe. That
  works in some cases with AssertError in unit test code but becomes
  problematic as such code becomes more complex.
 
 I'm mostly interested in letting the user know something went wrong and
 then exit the application.

That would be the most typical use case for catching an Error and certainly is 
the least risky of the reasons that you might do it.

- Jonathan M Davis


Re: Exception/Error division in D

2012-05-31 Thread Jacob Carlborg

On 2012-05-31 08:39, Jonathan M Davis wrote:


No. I haven't been arguing that. It's not particularly safe to catch Errors,
but they're catchable on purpose. It's catching and _handling_ an Error that's
generally a bad idea - that and continuing to execute after catching the Error
rather than letting the program terminate. It may be appropriate in very rare
examples where the programmer knows what they're doing, but in general,
catching them to do much beyond print out additional information or maybe do
some absolutely critical cleanup is a bad idea.

The real question is whether any cleanup should be attempted on Error (i.e.
destructors, scope statements, and finally blocks). Running that code is risky
when an Error occurs, because the program is in an invalid state. It's
possible that running it could actually do damage of some variety, depending
on the state of the program and what the cleanup does. But skipping all of
that cleanup can be a problem too, since that cleanup generally needs to be
done. Depending on what the Error was, the cleanup may actually work and
therefore leave the program in a less invalid state. So, it's a question of
whether attempting cleanup in an invalid state or skipping cleanup in an
invalid state is riskier. Per Walter, there's no guarantee that that cleanup
will occur, but with the current implementation it almost always does.


Ok, I'm sorry if I misunderstood you or confused you with someone else.

--
/Jacob Carlborg


Re: Exception/Error division in D

2012-05-31 Thread Jens Mueller
Walter Bright wrote:
 On 5/30/2012 2:32 AM, Don Clugston wrote:
 In fact, generally, the point of an AssertError is to prevent the program 
 from
 entering an invalid state.
 
 It's already in an invalid state when the assert fails, by definition.
 
 It is not recoverable. The only option is a more or less graceful shutdown.

How do I do a graceful shutdown if finally and scope is not guaranteed
to be executed? Assuming onAssertError, etc. is of no use because I need
to perform different shutdowns due to having different cases or if I
defined my own Error, let's say for some device.

Jens


Re: Exception/Error division in D

2012-05-31 Thread deadalnix

Le 31/05/2012 04:10, Walter Bright a écrit :

On 5/30/2012 5:58 PM, Kapps wrote:

All code has bugs in it. It's nice being notified about it and all,
but if you
release a server application, and it crashes every single time it
encounters any
bug... well, your customers will not have a fun time.


The correct response to a server app crashing is to restart it, not
attempt to keep a program in an invalid state running.



Should I mention to restart it AFTER A GRACEFUL SHUTDOWN ?


Re: Exception/Error division in D

2012-05-31 Thread deadalnix

Le 31/05/2012 03:06, Artur Skawina a écrit :

On 05/31/12 00:21, Jonathan M Davis wrote:

Now, it's perfectly possible to design code which never checks for null
pointers and if a null pointer is dereferenced throws an Exception and
attempts to recover from it (assuming that it's possible to detect the
dereference and throw at that point, which AFAIK is impossible with segfaults
- maybe it could be done on Windows with its Access Violations, but segfaults
trigger a signal handler, and you're screwed at that point). But writing code


No, it's easily recoverable. That does not mean however that it would be a good
idea to map segfaults to exceptions as a language feature. And dereferencing a
null pointer is *not* guaranteed to trap, all you need is a large enough offset
and you will get silent data corruption.

int i = 42;
auto j = cast(size_t)i;

ubyte* p = null;
p[j] = 13;
assert(i!=42); // oops

artur


Most system protect at least the first page (the first 4Kb ). For other 
it is doable within druntime with page protection.


For bigger stuff, they have to be forbidden in @safe code or runtime 
check should be added.


Re: Exception/Error division in D

2012-05-31 Thread deadalnix

Le 31/05/2012 04:17, Walter Bright a écrit :

On 5/30/2012 8:05 AM, Steven Schveighoffer wrote:

I'd classify errors/exceptions into three categories:

1. corruption/segfault -- not recoverable under any reasonable
circumstances.
Special cases exist (such as a custom paging mechanism).
2. program invariant errors (i.e. assert errors) -- Recovery is not
defined by
the runtime, so you must do it manually. Any decision the runtime
makes will be
arbitrary, and could be wrong.
3. try/catch exceptions -- these are planned for and *expected* to
occur because
the program cannot control it's environment. e.g. EOF when none was
expected.



A recoverable exception is NOT a logic bug in your program, which is why
it is recoverable.

If there is recovery possible from a particular assert error, then you
are using asserts incorrectly. Assert errors occur because your program
has entered an unanticipated, invalid state. There's no such thing as
knowing how to put it back into a valid state, because you don't know
where it went wrong and how much is corrupted, etc.


A failure in database component should prevent me from close a network 
connection properly in an unrelated part of the program.


This is called failing gracefully. And this highly recommended, and you 
KNOW that the system will fail at some point.


Re: Exception/Error division in D

2012-05-31 Thread deadalnix

Le 31/05/2012 00:21, Jonathan M Davis a écrit :

On Thursday, May 31, 2012 00:01:16 deadalnix wrote:

Le 30/05/2012 17:29, Don Clugston a écrit :

There's a big difference. A segfault is a machine error. The integrity
of the machine model has been violated, and the machine is in an
out-of-control state. In particular, the stack may be corrupted, so
stack unwinding may not be successful.

But, in an assert error, the machine is completely intact; the error is
at a higher level, which does not interfere with stack unwinding.

Damage is possible only if you've written your destructors/finally code
extremely poorly. Note that, unlike C++, it's OK to throw a new Error or
Exception from inside a destructor.
But with (say) a stack overflow, you don't necessarily know what code is
being executed. It could do anything.


Most segfault are null deference or unintizialized pointer deference.
Both are recoverable.


If you dereferenced a null pointer, it's a bug in your code. Your code is
assuming that the pointer was non-null, which was obviously incorrect, because
it was null. That's _not_ recoverable in the general case. Your code was
obviously written with the assumption that the pointer was non-null, so your
code is wrong, and so continuing to execute it makes no sense, because it's in
an invalid state and could do who-knows-what. If there's any possibility of a
pointer being null, the correct thing to do is to check it before
dereferencing it. If you don't, it's bug.



I want to remind you that the subject is knowing if scope and finally 
block should be triggered by errors.


Such blocks are perfectly safe to execute in such a situation.

Additionally, I may want to abort the current operation, but not the 
whole program. This is doable on such an error.



Now, it's perfectly possible to design code which never checks for null
pointers and if a null pointer is dereferenced throws an Exception and
attempts to recover from it (assuming that it's possible to detect the
dereference and throw at that point, which AFAIK is impossible with segfaults
- maybe it could be done on Windows with its Access Violations, but segfaults
trigger a signal handler, and you're screwed at that point).


Well, I have a pull request in druntime that do exactly what you claim 
is impossible.


Re: Exception/Error division in D

2012-05-31 Thread Regan Heath
On Wed, 30 May 2012 22:36:50 +0100, Jonathan M Davis jmdavisp...@gmx.com  
wrote:
In general, a segfault is definitely worse, but logic errors can_ be  
just as bad in terms of the damage that they can do (especially in  
cmparison with

segfaults caused by null pointers as opposed to those caused by memory
corruption). It all depends on what the logic error is and what happens  
if you try and continue with the program in such a state.


In fact.. a logic error - or rather an assert triggered by a bad argument  
or similar may be the result of memory corruption which was undetected  
i.e. buffer overflow on the stack overwriting an integer passed to a  
function which asserts it is within a range, and it isn't.  So, you can't  
even be sure that logic errors aren't caused by memory corruption.


R

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Exception/Error division in D

2012-05-31 Thread Lars T. Kyllingstad

On Thursday, 31 May 2012 at 02:18:22 UTC, Walter Bright wrote:

On 5/30/2012 8:05 AM, Steven Schveighoffer wrote:

I'd classify errors/exceptions into three categories:

1. corruption/segfault -- not recoverable under any reasonable 
circumstances.

Special cases exist (such as a custom paging mechanism).
2. program invariant errors (i.e. assert errors) -- Recovery 
is not defined by
the runtime, so you must do it manually. Any decision the 
runtime makes will be

arbitrary, and could be wrong.
3. try/catch exceptions -- these are planned for and 
*expected* to occur because
the program cannot control it's environment. e.g. EOF when 
none was expected.



A recoverable exception is NOT a logic bug in your program, 
which is why it is recoverable.


If there is recovery possible from a particular assert error, 
then you are using asserts incorrectly.


I think this is a key point.  Asserts are there to verify and 
debug program logic, they are not part of the logic itself.  They 
are a useful tool for the programmer, nothing more.  
Specifically, asserts are NOT an error handling mechanism!


If you compile the code with -release (which is often the case 
for production code), the asserts won't even be included.  
Therefore, when designing the error handling mechanisms for a 
program, one should just pretend the asserts aren't there.  There 
is no point in writing code which shuts down gracefully when it 
is compiled without -release, but trudges on in an invalid state 
when compiled in release mode.  Then you should have been using 
enforce() instead.


-Lars



Re: Exception/Error division in D

2012-05-31 Thread deadalnix

Le 31/05/2012 11:23, Lars T. Kyllingstad a écrit :

On Thursday, 31 May 2012 at 02:18:22 UTC, Walter Bright wrote:

On 5/30/2012 8:05 AM, Steven Schveighoffer wrote:

I'd classify errors/exceptions into three categories:

1. corruption/segfault -- not recoverable under any reasonable
circumstances.
Special cases exist (such as a custom paging mechanism).
2. program invariant errors (i.e. assert errors) -- Recovery is not
defined by
the runtime, so you must do it manually. Any decision the runtime
makes will be
arbitrary, and could be wrong.
3. try/catch exceptions -- these are planned for and *expected* to
occur because
the program cannot control it's environment. e.g. EOF when none was
expected.



A recoverable exception is NOT a logic bug in your program, which is
why it is recoverable.

If there is recovery possible from a particular assert error, then you
are using asserts incorrectly.


I think this is a key point. Asserts are there to verify and debug
program logic, they are not part of the logic itself. They are a useful
tool for the programmer, nothing more. Specifically, asserts are NOT an
error handling mechanism!

If you compile the code with -release (which is often the case for
production code), the asserts won't even be included. Therefore, when
designing the error handling mechanisms for a program, one should just
pretend the asserts aren't there. There is no point in writing code
which shuts down gracefully when it is compiled without -release, but
trudges on in an invalid state when compiled in release mode. Then you
should have been using enforce() instead.

-Lars



Your are lost in the details of that specific case. assert is a very 
specific issue. What is discussed here is much broader.


Re: Exception/Error division in D

2012-05-31 Thread Walter Bright

On 5/31/2012 12:40 AM, Jens Mueller wrote:

How do I do a graceful shutdown if finally and scope is not guaranteed
to be executed? Assuming onAssertError, etc. is of no use because I need
to perform different shutdowns due to having different cases or if I
defined my own Error, let's say for some device.


There's no way to guarantee a graceful shutdown.

No way.

If you must have such, then the way to do it is to divide your application into 
separate processes that communicate via interprocess communication, then when 
one component fails the rest of your app can restart it or do what's necessary, 
as the rest is not in an invalid state.




Re: Exception/Error division in D

2012-05-31 Thread Walter Bright

On 5/31/2012 2:06 AM, deadalnix wrote:

A failure in database component should prevent me from close a network
connection properly in an unrelated part of the program.


It *is* related if the process space is shared. The correct way to do what 
you're proposing is to make each component a separate process. Then, you are 
guaranteed that the failure of one component is separable, and restartable.




This is called failing gracefully. And this highly recommended, and you KNOW
that the system will fail at some point.


In a shared memory space, you have no guarantees whatsoever that the failure in 
the component is not a failure in the rest of the program. You cannot tell if it 
is related or not.


Re: Exception/Error division in D

2012-05-31 Thread Jens Mueller
Walter Bright wrote:
 On 5/31/2012 12:40 AM, Jens Mueller wrote:
 How do I do a graceful shutdown if finally and scope is not guaranteed
 to be executed? Assuming onAssertError, etc. is of no use because I need
 to perform different shutdowns due to having different cases or if I
 defined my own Error, let's say for some device.
 
 There's no way to guarantee a graceful shutdown.
 
 No way.
 
 If you must have such, then the way to do it is to divide your
 application into separate processes that communicate via
 interprocess communication, then when one component fails the rest
 of your app can restart it or do what's necessary, as the rest is
 not in an invalid state.

Okay, let's assume I have separate processes maybe even processes on
different machines. In one process I get an error. Let's say I want to
trigger the other process that it restarts the process or just logs the
event whatever makes sense.
How do I do this if it not guaranteed that finally/scope blocks are
being executed?

I don't need a guarantee that the shutdown will work in each and every
case. All I need is the possibility to perform a more graceful shutdown.

Jens


Re: Exception/Error division in D

2012-05-31 Thread Sean Kelly
On May 31, 2012, at 1:05 PM, Jens Mueller jens.k.muel...@gmx.de wrote:

 Walter Bright wrote:
 On 5/31/2012 12:40 AM, Jens Mueller wrote:
 How do I do a graceful shutdown if finally and scope is not guaranteed
 to be executed? Assuming onAssertError, etc. is of no use because I need
 to perform different shutdowns due to having different cases or if I
 defined my own Error, let's say for some device.
 
 There's no way to guarantee a graceful shutdown.
 
 No way.
 
 If you must have such, then the way to do it is to divide your
 application into separate processes that communicate via
 interprocess communication, then when one component fails the rest
 of your app can restart it or do what's necessary, as the rest is
 not in an invalid state.
 
 Okay, let's assume I have separate processes maybe even processes on
 different machines. In one process I get an error. Let's say I want to
 trigger the other process that it restarts the process or just logs the
 event whatever makes sense.
 How do I do this if it not guaranteed that finally/scope blocks are
 being executed?
 
 I don't need a guarantee that the shutdown will work in each and every
 case. All I need is the possibility to perform a more graceful shutdown.

You pretty much need a local process monitor. This is needed anyway, since not 
every failure may throw. Say SIGBUS on Posix, for example. 

Re: Exception/Error division in D

2012-05-31 Thread Walter Bright

On 5/31/2012 1:05 PM, Jens Mueller wrote:

Okay, let's assume I have separate processes maybe even processes on
different machines. In one process I get an error. Let's say I want to
trigger the other process that it restarts the process or just logs the
event whatever makes sense.
How do I do this if it not guaranteed that finally/scope blocks are
being executed?



Presumably the operating system provides a means to tell when a process is no 
longer running as part of its inter-process communication api.


Re: Exception/Error division in D

2012-05-31 Thread Walter Bright

On 5/31/2012 2:23 AM, Lars T. Kyllingstad wrote:

On Thursday, 31 May 2012 at 02:18:22 UTC, Walter Bright wrote:

A recoverable exception is NOT a logic bug in your program, which is why it is
recoverable.

If there is recovery possible from a particular assert error, then you are
using asserts incorrectly.


I think this is a key point. Asserts are there to verify and debug program
logic, they are not part of the logic itself. They are a useful tool for the
programmer, nothing more. Specifically, asserts are NOT an error handling
mechanism!


Right. And I'd like to amplify that the asserts are also there to detect program 
faults hopefully before damage is done.


If a program must continue even after it has failed, then you have a WRONGLY 
designed system.


It is extremely important to understand this point if you are implementing any 
sort of critical software.


Re: Exception/Error division in D

2012-05-30 Thread deadalnix

Le 24/05/2012 12:27, Denis Shelomovskij a écrit :

Let's talk about an abstract situation without caring about breaking
existing code, current docs, implementation etc.

Definitions:
* an Exception is something that tigers scope guards and executes
catch/finally blocks if thrown;
* an Error is something that doesn't do it.

As a result _we can't do any clean-up if an Error is thrown_ because
scope guards and catch/finally blocks aren't executed and the program is
in invalid state because of this. Of course it's theoretically possible
to code without scope guards and catch/finally blocks but isn't
applicably for a real project. E.g. in some editor if and Error is
thrown there is no ability to save opened documents.


Main Question: What do you think can be an Error?

Can Integer Divide by Zero be an Error? Definitely, not.

Can Access Violation be an Error? No, because it's very common to
access a field/virtual member function of a null object.

Can Out of memory be an Error? No, because e.g. if I read a user file
that require me to create a large array ( 100 MiB, e.g.) I don't want
to crash, but just tell, that Dear user, the file can't be opened
because it requires...


So what am I think can be an Error? IMHO, nothing. Because throwing
everything can indicate that program in very good/terribly bad state and
compiler doesn't know anything about that. And because fatal error is
fatal the program should just try to print error and close instead of
throwing something.


Let's now return to the real D world. Current implementation treats
Errors as Exceptions for now. Documentation keeps silence. All listed
can't be an error cases are Errors (and it's terrible).

So why do we has Exception/Error division in D? Because of nothrow.
Personally I don't need nothrow for that high cost of making D unusable
for me. Lets realize and solve Exception/Error problem and solve nothrow
in the second place.


Related links:
http://forum.dlang.org/thread/1566418.J7qGkEti3s@lyonel
http://d.puremagic.com/issues/show_bug.cgi?id=8135
http://d.puremagic.com/issues/show_bug.cgi?id=8136
http://d.puremagic.com/issues/show_bug.cgi?id=8137


P.S.
By the way, the only problem I see in current implementation is a luck
of Object finalized assertion (True disposable objects (add
Finalized! assertion) NG thread that didn't interest anybody).



The fact that error don't trigger scope and everything is nonsensial.

Today, we know how to implement exception with NO RUNTIME COST when 
exception isn't thrown. No reason not to do it, except executable size. 
As this is a specific constraint, we may want to enable it by a compiler 
switch, but not by default.


I see Error as problem that can occur anywhere in any piece of code.

I think D have some flaw in Exception management. See Segfault vs 
NullPointerException discussions in that very forum. Segfault may be OK 
for some application, but not for a server app that need to be robust.


Error exists because of nothrow. As some exceptions can be thrown 
ANYWHERE, we need a way to separate what is expected to fail, and that 
have to be handled to be nothrow, and what can go wrong anywhere 
(basically, when druntime cannot do its job for some reasons).


Re: Exception/Error division in D

2012-05-30 Thread deadalnix

Le 24/05/2012 20:39, Steven Schveighoffer a écrit :

I'd argue this is unrecoverable. Access Violation results from
corruption, and the damage has already been done. Even a null pointer
access can be the cause of previous corruption. There is no recovery
from memory corruption. There is no way to plan for it.

Now, if you want to handle it specifically for your program, that should
be doable, at your own risk. But there's no way throwing an Exception is
a valid result.



https://github.com/D-Programming-Language/druntime/pull/187

I think this is a mandatory patch due to nullable types by default. 
Arguably, nullable by default is the problem.


Re: Exception/Error division in D

2012-05-30 Thread deadalnix

Le 24/05/2012 21:33, Sean Kelly a écrit :

On May 24, 2012, at 11:39 AM, Steven Schveighoffer wrote:


On Thu, 24 May 2012 06:27:12 -0400, Denis 
Shelomovskijverylonglogin@gmail.com  wrote:


Let's talk about an abstract situation without caring about breaking existing 
code, current docs, implementation etc.

Definitions:
* an Exception is something that tigers scope guards and executes catch/finally 
blocks if thrown;
* an Error is something that doesn't do it.


I'll give you a different definition:

* an Exception is something that can be handled far away from the context of 
the error, because the system can safely unwind the stack.
* an Error must be handled at the point the error occurred, or the program 
state is by definition invalid.


This is a good point.  OutOfMemory conditions aside, the only time I'd want to 
recover from an Error condition was at the point the event occurred, not 
somewhere up the stack.



Often, the point of Exception isn't to recover, but to fail as cleanly 
as possible. To do so, Error must trigger finally blocks and scope 
statement.


They probably shouldn't be catchable in @safe code because of the 
possible invalid state of the program.


But still, often recovering isn't the point when it come to problem as 
bad as Errors.


Re: Exception/Error division in D

2012-05-30 Thread deadalnix

Le 29/05/2012 18:53, Sean Kelly a écrit :

On May 24, 2012, at 11:50 PM, Jacob Carlborg wrote:


On 2012-05-24 21:33, Sean Kelly wrote:


This is a good point.  OutOfMemory conditions aside, the only time I'd want to 
recover from an Error condition was at the point the event occurred, not 
somewhere up the stack.


You never feel you want to catch at the top level, print a sensible error 
message and then exit the application? Instead of the application just 
disappearing for user.


Well sure, but I wouldn't consider this recovery.


As said, recovery isn't the only point of exceptions. For problems as 
bad as this, you often want to fail cleanly, eventually print an error 
message or something.


Exception handling discussion are often very focussed on recovery, but 
the fact is that it is A use case, but not THE use case.


It is very common in real case that you cannot recover from some 
problems, and just want to fail without messing everything up.


Re: Exception/Error division in D

2012-05-30 Thread Jonathan M Davis
On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:
 The fact that error don't trigger scope and everything is nonsensial.

If an Error is truly unrecoverable (as they're generally supposed to be), then 
what does it matter? Something fatal occured in your program, so it 
terminates. Because it's an Error, you can get a stack trace and report 
something before the program actually terminates, but continuing execution 
after an Error is considered to be truly _bad_ idea, so in general, why does 
it matter whether scope statements, finally blocks, or destructors get 
executed? It's only rarer cases where you're trying to do something like 
create a unit test framework on top of assert that you would need to catch an 
Error, and that's questionable enough as it is. In normal program execution, 
an error is fatal, so cleanup is irrelevant and even potentially dangerous, 
because your program is already in an invalid state.

- Jonathan M Davis


Re: Exception/Error division in D

2012-05-30 Thread Dmitry Olshansky

On 30.05.2012 12:33, deadalnix wrote:

Le 24/05/2012 21:33, Sean Kelly a écrit :

On May 24, 2012, at 11:39 AM, Steven Schveighoffer wrote:


On Thu, 24 May 2012 06:27:12 -0400, Denis
Shelomovskijverylonglogin@gmail.com wrote:


Let's talk about an abstract situation without caring about breaking
existing code, current docs, implementation etc.

Definitions:
* an Exception is something that tigers scope guards and executes
catch/finally blocks if thrown;
* an Error is something that doesn't do it.


I'll give you a different definition:

* an Exception is something that can be handled far away from the
context of the error, because the system can safely unwind the stack.
* an Error must be handled at the point the error occurred, or the
program state is by definition invalid.


This is a good point. OutOfMemory conditions aside, the only time I'd
want to recover from an Error condition was at the point the event
occurred, not somewhere up the stack.



Often, the point of Exception isn't to recover, but to fail as cleanly
as possible. To do so, Error must trigger finally blocks and scope
statement.


Yes, finally the voice of wisdom!



They probably shouldn't be catchable in @safe code because of the
possible invalid state of the program.


Interesting point btw.


But still, often recovering isn't the point when it come to problem as
bad as Errors.



--
Dmitry Olshansky


Re: Exception/Error division in D

2012-05-30 Thread Don Clugston

On 30/05/12 10:40, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:

The fact that error don't trigger scope and everything is nonsensial.


If an Error is truly unrecoverable (as they're generally supposed to be), then
what does it matter? Something fatal occured in your program, so it
terminates. Because it's an Error, you can get a stack trace and report
something before the program actually terminates, but continuing execution
after an Error is considered to be truly _bad_ idea, so in general, why does
it matter whether scope statements, finally blocks, or destructors get
executed? It's only rarer cases where you're trying to do something like
create a unit test framework on top of assert that you would need to catch an
Error, and that's questionable enough as it is. In normal program execution,
an error is fatal, so cleanup is irrelevant and even potentially dangerous,
because your program is already in an invalid state.


That's true for things like segfaults, but in the case of an 
AssertError, there's no reason to believe that cleanup would cause any 
damage.
In fact, generally, the point of an AssertError is to prevent the 
program from entering an invalid state.

And it's very valuable to log it properly.


Re: Exception/Error division in D

2012-05-30 Thread Jonathan M Davis
On Wednesday, May 30, 2012 11:32:00 Don Clugston wrote:
 On 30/05/12 10:40, Jonathan M Davis wrote:
  On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:
  The fact that error don't trigger scope and everything is nonsensial.
  
  If an Error is truly unrecoverable (as they're generally supposed to be),
  then what does it matter? Something fatal occured in your program, so it
  terminates. Because it's an Error, you can get a stack trace and report
  something before the program actually terminates, but continuing
  execution after an Error is considered to be truly _bad_ idea, so in
  general, why does it matter whether scope statements, finally blocks, or
  destructors get executed? It's only rarer cases where you're trying to do
  something like create a unit test framework on top of assert that you
  would need to catch an Error, and that's questionable enough as it is. In
  normal program execution, an error is fatal, so cleanup is irrelevant and
  even potentially dangerous, because your program is already in an invalid
  state.
 
 That's true for things like segfaults, but in the case of an
 AssertError, there's no reason to believe that cleanup would cause any
 damage.
 In fact, generally, the point of an AssertError is to prevent the
 program from entering an invalid state.

An assertion failure really isn't all that different from a segfault. By 
definition, if an assertion fails, the program is an invalid state, because the 
whole point of the assertion is to guarantee something about the program's 
state. Now, if a segfault occurs (particularly if it's caused by something 
other than a null pointer), the program is likely to be in a _worse_ state, 
but it's in an invalid state in either case. In neither case does it make any 
sense to try and recover, and in both cases, there's a definite risk in 
executing any further code - including cleanup code. Yes, the segfault is 
probably worse but not necessarily all that much worse. A logic error can be 
just as insidious to the state of a program as memory corruption, depending on 
what it is.

 And it's very valuable to log it properly.

Yes, which is why it's better to have an Error thrown rather than a halt 
instruction be executed. But that doesn't mean that any attempt at cleanup is 
any more valid.

- Jonathan M Davis


Re: Exception/Error division in D

2012-05-30 Thread Jacob Carlborg

On 2012-05-30 12:59, Jonathan M Davis wrote:


Yes, which is why it's better to have an Error thrown rather than a halt
instruction be executed. But that doesn't mean that any attempt at cleanup is
any more valid.


If you're not supposed to be able to catch Errors then what's the 
difference?


--
/Jacob Carlborg


Re: Exception/Error division in D

2012-05-30 Thread Dmitry Olshansky

On 30.05.2012 17:28, Jacob Carlborg wrote:

On 2012-05-30 12:59, Jonathan M Davis wrote:


Yes, which is why it's better to have an Error thrown rather than a halt
instruction be executed. But that doesn't mean that any attempt at
cleanup is
any more valid.


If you're not supposed to be able to catch Errors then what's the
difference?



Having half-flushed/synced database file is no good. I've had pleasure 
of restoring such things by hand. Trust me, you DON'T want it.


A common technique that can kick start half-flushed binary file is 
appending certain amount of zeros until it fits. Depending on 
structure it may need more then that.


--
Dmitry Olshansky


Re: Exception/Error division in D

2012-05-30 Thread deadalnix

Le 30/05/2012 11:32, Don Clugston a écrit :

On 30/05/12 10:40, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:

The fact that error don't trigger scope and everything is nonsensial.


If an Error is truly unrecoverable (as they're generally supposed to
be), then
what does it matter? Something fatal occured in your program, so it
terminates. Because it's an Error, you can get a stack trace and report
something before the program actually terminates, but continuing
execution
after an Error is considered to be truly _bad_ idea, so in general,
why does
it matter whether scope statements, finally blocks, or destructors get
executed? It's only rarer cases where you're trying to do something like
create a unit test framework on top of assert that you would need to
catch an
Error, and that's questionable enough as it is. In normal program
execution,
an error is fatal, so cleanup is irrelevant and even potentially
dangerous,
because your program is already in an invalid state.


That's true for things like segfaults, but in the case of an
AssertError, there's no reason to believe that cleanup would cause any
damage.
In fact, generally, the point of an AssertError is to prevent the
program from entering an invalid state.
And it's very valuable to log it properly.


For segfault, it has been proven to be useful in other languages.


Re: Exception/Error division in D

2012-05-30 Thread deadalnix

Le 30/05/2012 12:59, Jonathan M Davis a écrit :

And it's very valuable to log it properly.


Yes, which is why it's better to have an Error thrown rather than a halt
instruction be executed. But that doesn't mean that any attempt at cleanup is
any more valid.



Sorry but that is bullshit. What can be the benefit of not trying to 
clean things up ?


Do you really consider that corrupted files, client waiting forever at 
the other end of a connection or any similar stuff is a good thing ? 
Because that is what you are advocating.


I may sound good on the paper, but in real life, system DOES fail. It 
isn't a question of if, but a question of when and how often, and what 
to do about it.


Re: Exception/Error division in D

2012-05-30 Thread Sean Kelly
On May 30, 2012, at 7:21 AM, deadalnix deadal...@gmail.com wrote:

 Le 30/05/2012 12:59, Jonathan M Davis a écrit :
 And it's very valuable to log it properly.
 
 Yes, which is why it's better to have an Error thrown rather than a halt
 instruction be executed. But that doesn't mean that any attempt at cleanup is
 any more valid.
 
 
 Sorry but that is bullshit. What can be the benefit of not trying to clean 
 things up ?
 
 Do you really consider that corrupted files, client waiting forever at the 
 other end of a connection or any similar stuff is a good thing ? Because that 
 is what you are advocating.
 
 I may sound good on the paper, but in real life, system DOES fail. It isn't a 
 question of if, but a question of when and how often, and what to do about it.

I'd certainly at least want to be given the option of cleaning up when an Error 
is thrown.  If not, I have a feeling that in circumstances where I really 
wanted it I'd do something horrible to make sure it happened in some other way. 

Re: Exception/Error division in D

2012-05-30 Thread Steven Schveighoffer

On Wed, 30 May 2012 05:32:00 -0400, Don Clugston d...@nospam.com wrote:


On 30/05/12 10:40, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:

The fact that error don't trigger scope and everything is nonsensial.


If an Error is truly unrecoverable (as they're generally supposed to  
be), then

what does it matter? Something fatal occured in your program, so it
terminates. Because it's an Error, you can get a stack trace and report
something before the program actually terminates, but continuing  
execution
after an Error is considered to be truly _bad_ idea, so in general, why  
does

it matter whether scope statements, finally blocks, or destructors get
executed? It's only rarer cases where you're trying to do something like
create a unit test framework on top of assert that you would need to  
catch an
Error, and that's questionable enough as it is. In normal program  
execution,
an error is fatal, so cleanup is irrelevant and even potentially  
dangerous,

because your program is already in an invalid state.


That's true for things like segfaults, but in the case of an  
AssertError, there's no reason to believe that cleanup would cause any  
damage.


There's also no reason to assume that orderly cleanup *doesn't* cause any  
damage.  In fact, it's not reasonable to assume *anything*.


Which is the point.  If you want to recover from an error, you have to do  
it manually.  It should be doable, but the default handling should not  
need to be defined (i.e. implementations should be free to do whatever  
they want).


But there is no reasonable *default* for handling an error that the  
runtime can assume.


I'd classify errors/exceptions into three categories:

1. corruption/segfault -- not recoverable under any reasonable  
circumstances.  Special cases exist (such as a custom paging mechanism).
2. program invariant errors (i.e. assert errors) --  Recovery is not  
defined by the runtime, so you must do it manually.  Any decision the  
runtime makes will be arbitrary, and could be wrong.
3. try/catch exceptions -- these are planned for and *expected* to occur  
because the program cannot control it's environment.  e.g. EOF when none  
was expected.


The largest problem with the difference between 2 and 3 is the actual  
decision of whether an exceptional case is categorized as 2 or 3 can be  
decoupled from the code that decides between them.


For example:

double invert(double x)
{
   assertOrEnfoce?(x != 0); // which should it be?
   return 1.0/x;
}

case 1:

void main()
{
writeln(invert(0)); // clearly a program error
}

case 2:

int main(string[] args)
{
   writeln(invert(to!double(args[1])); // clearly a catchable error
}

I don't know of a good way to solve that...

-Steve


Re: Exception/Error division in D

2012-05-30 Thread Sean Kelly
On May 30, 2012, at 8:05 AM, Steven Schveighoffer schvei...@yahoo.com wrote:

 On Wed, 30 May 2012 05:32:00 -0400, Don Clugston d...@nospam.com wrote:
 
 On 30/05/12 10:40, Jonathan M Davis wrote:
 On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:
 The fact that error don't trigger scope and everything is nonsensial.
 
 If an Error is truly unrecoverable (as they're generally supposed to be), 
 then
 what does it matter? Something fatal occured in your program, so it
 terminates. Because it's an Error, you can get a stack trace and report
 something before the program actually terminates, but continuing execution
 after an Error is considered to be truly _bad_ idea, so in general, why does
 it matter whether scope statements, finally blocks, or destructors get
 executed? It's only rarer cases where you're trying to do something like
 create a unit test framework on top of assert that you would need to catch 
 an
 Error, and that's questionable enough as it is. In normal program execution,
 an error is fatal, so cleanup is irrelevant and even potentially dangerous,
 because your program is already in an invalid state.
 
 That's true for things like segfaults, but in the case of an AssertError, 
 there's no reason to believe that cleanup would cause any damage.
 
 There's also no reason to assume that orderly cleanup *doesn't* cause any 
 damage.  In fact, it's not reasonable to assume *anything*.
 
 Which is the point.  If you want to recover from an error, you have to do it 
 manually.  It should be doable, but the default handling should not need to 
 be defined (i.e. implementations should be free to do whatever they want).
 
 But there is no reasonable *default* for handling an error that the runtime 
 can assume.
 
 I'd classify errors/exceptions into three categories:
 
 1. corruption/segfault -- not recoverable under any reasonable circumstances. 
  Special cases exist (such as a custom paging mechanism).
 2. program invariant errors (i.e. assert errors) --  Recovery is not defined 
 by the runtime, so you must do it manually.  Any decision the runtime makes 
 will be arbitrary, and could be wrong.
 3. try/catch exceptions -- these are planned for and *expected* to occur 
 because the program cannot control it's environment.  e.g. EOF when none was 
 expected.
 
 The largest problem with the difference between 2 and 3 is the actual 
 decision of whether an exceptional case is categorized as 2 or 3 can be 
 decoupled from the code that decides between them.
 
 For example:
 
 double invert(double x)
 {
   assertOrEnfoce?(x != 0); // which should it be?
   return 1.0/x;
 }
 
 case 1:
 
 void main()
 {
writeln(invert(0)); // clearly a program error
 }
 
 case 2:
 
 int main(string[] args)
 {
   writeln(invert(to!double(args[1])); // clearly a catchable error
 }
 
 I don't know of a good way to solve that...

Sounds like a good argument for the assert handler in core.runtime. 

Re: Exception/Error division in D

2012-05-30 Thread Don Clugston

On 30/05/12 12:59, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 11:32:00 Don Clugston wrote:

On 30/05/12 10:40, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:

The fact that error don't trigger scope and everything is nonsensial.


If an Error is truly unrecoverable (as they're generally supposed to be),
then what does it matter? Something fatal occured in your program, so it
terminates. Because it's an Error, you can get a stack trace and report
something before the program actually terminates, but continuing
execution after an Error is considered to be truly _bad_ idea, so in
general, why does it matter whether scope statements, finally blocks, or
destructors get executed? It's only rarer cases where you're trying to do
something like create a unit test framework on top of assert that you
would need to catch an Error, and that's questionable enough as it is. In
normal program execution, an error is fatal, so cleanup is irrelevant and
even potentially dangerous, because your program is already in an invalid
state.


That's true for things like segfaults, but in the case of an
AssertError, there's no reason to believe that cleanup would cause any
damage.
In fact, generally, the point of an AssertError is to prevent the
program from entering an invalid state.


An assertion failure really isn't all that different from a segfault. By
definition, if an assertion fails, the program is an invalid state, because the
whole point of the assertion is to guarantee something about the program's
state.


There's a big difference. A segfault is a machine error. The integrity 
of the machine model has been violated, and the machine is in an 
out-of-control state. In particular, the stack may be corrupted, so 
stack unwinding may not be successful.


But, in an assert error, the machine is completely intact; the error is 
at a higher level, which does not interfere with stack unwinding.


Damage is possible only if you've written your destructors/finally code 
extremely poorly. Note that, unlike C++, it's OK to throw a new Error or 
Exception from inside a destructor.
But with (say) a stack overflow, you don't necessarily know what code is 
being executed. It could do anything.




Now, if a segfault occurs (particularly if it's caused by something
other than a null pointer), the program is likely to be in a _worse_ state,
but it's in an invalid state in either case. In neither case does it make any
sense to try and recover, and in both cases, there's a definite risk in
executing any further code - including cleanup code.



Yes, the segfault is
probably worse but not necessarily all that much worse. A logic error can be
just as insidious to the state of a program as memory corruption, depending on
what it is.


I'm surprised by your response, I didn't think this was controversial.
We could just as easily have said assert() throws an AssertException.
(Or have two kinds of assert, one which is an Error and the other merely 
an Exception).




Re: Exception/Error division in D

2012-05-30 Thread Jens Mueller
Steven Schveighoffer wrote:
 On Wed, 30 May 2012 05:32:00 -0400, Don Clugston d...@nospam.com wrote:
 
 On 30/05/12 10:40, Jonathan M Davis wrote:
 On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:
 The fact that error don't trigger scope and everything is nonsensial.
 
 If an Error is truly unrecoverable (as they're generally
 supposed to be), then
 what does it matter? Something fatal occured in your program, so it
 terminates. Because it's an Error, you can get a stack trace and report
 something before the program actually terminates, but continuing
 execution
 after an Error is considered to be truly _bad_ idea, so in
 general, why does
 it matter whether scope statements, finally blocks, or destructors get
 executed? It's only rarer cases where you're trying to do something like
 create a unit test framework on top of assert that you would
 need to catch an
 Error, and that's questionable enough as it is. In normal
 program execution,
 an error is fatal, so cleanup is irrelevant and even potentially
 dangerous,
 because your program is already in an invalid state.
 
 That's true for things like segfaults, but in the case of an
 AssertError, there's no reason to believe that cleanup would cause
 any damage.
 
 There's also no reason to assume that orderly cleanup *doesn't*
 cause any damage.  In fact, it's not reasonable to assume
 *anything*.
 
 Which is the point.  If you want to recover from an error, you have
 to do it manually.  It should be doable, but the default handling
 should not need to be defined (i.e. implementations should be free
 to do whatever they want).
 
 But there is no reasonable *default* for handling an error that the
 runtime can assume.
 
 I'd classify errors/exceptions into three categories:
 
 1. corruption/segfault -- not recoverable under any reasonable
 circumstances.  Special cases exist (such as a custom paging
 mechanism).
 2. program invariant errors (i.e. assert errors) --  Recovery is not
 defined by the runtime, so you must do it manually.  Any decision
 the runtime makes will be arbitrary, and could be wrong.
 3. try/catch exceptions -- these are planned for and *expected* to
 occur because the program cannot control it's environment.  e.g. EOF
 when none was expected.
 
 The largest problem with the difference between 2 and 3 is the
 actual decision of whether an exceptional case is categorized as 2
 or 3 can be decoupled from the code that decides between them.
 
 For example:
 
 double invert(double x)
 {
assertOrEnfoce?(x != 0); // which should it be?
return 1.0/x;
 }

It's a logic error. Thus,

double invert(double x)
in { assert(x != 0); }
body
{
   return 1.0/x;
}

 case 1:
 
 void main()
 {
 writeln(invert(0)); // clearly a program error
 }

Obviously a logic error.

 case 2:
 
 int main(string[] args)
 {
writeln(invert(to!double(args[1])); // clearly a catchable error
 }

This should be
int main(string[] args)
{
   auto arg = to!double(args[1]);
   enforce(arg != 0);
   writeln(invert(arg));
}

The enforce is needed because args[1] is user input. If the programmer
controlled the value of arg and believes arg != 0 always holds then no
enforce would be needed.

Doesn't this make sense?

Jens

PS
For the record, I think (like most) that Errors should like Exceptions
work with scope, etc. The only arguments against is the theoretical
possibility of causing more damage while cleaning up. I say theoretical
because there was no practical example given. It seems that it may cause
more damage but it does not need to. Of course, if damage happens it's
the programmers fault but it's also the programmer's fault if he does
not try to do a graceful shutdown, i.e. closing sockets, sending a crash
report, or similar.


Re: Exception/Error division in D

2012-05-30 Thread Dmitry Olshansky

On 30.05.2012 19:05, Steven Schveighoffer wrote:

On Wed, 30 May 2012 05:32:00 -0400, Don Clugston d...@nospam.com wrote:


On 30/05/12 10:40, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:

The fact that error don't trigger scope and everything is nonsensial.


If an Error is truly unrecoverable (as they're generally supposed to
be), then
what does it matter? Something fatal occured in your program, so it
terminates. Because it's an Error, you can get a stack trace and report
something before the program actually terminates, but continuing
execution
after an Error is considered to be truly _bad_ idea, so in general,
why does
it matter whether scope statements, finally blocks, or destructors get
executed? It's only rarer cases where you're trying to do something like
create a unit test framework on top of assert that you would need to
catch an
Error, and that's questionable enough as it is. In normal program
execution,
an error is fatal, so cleanup is irrelevant and even potentially
dangerous,
because your program is already in an invalid state.


That's true for things like segfaults, but in the case of an
AssertError, there's no reason to believe that cleanup would cause any
damage.


There's also no reason to assume that orderly cleanup *doesn't* cause
any damage. In fact, it's not reasonable to assume *anything*.

Which is the point. If you want to recover from an error, you have to do
it manually. It should be doable, but the default handling should not
need to be defined (i.e. implementations should be free to do whatever
they want).

But there is no reasonable *default* for handling an error that the
runtime can assume.



I'd say that calling scope, destructors etc. on Error being thrown is 
the most _useful_ thing in all cases. If you realy-realy afraid of 
memory corruption killing sensitive data, taking control of OS and so on 
-  you just catch Errors early on inside such sensitive functions. And 
call C's abort(). And that's it.


Let's make common and hard case default and automatic plz.

--
Dmitry Olshansky


Re: Exception/Error division in D

2012-05-30 Thread Steven Schveighoffer
On Wed, 30 May 2012 11:47:34 -0400, Jens Mueller jens.k.muel...@gmx.de  
wrote:



Steven Schveighoffer wrote:



case 2:

int main(string[] args)
{
   writeln(invert(to!double(args[1])); // clearly a catchable error
}


This should be
int main(string[] args)
{
   auto arg = to!double(args[1]);
   enforce(arg != 0);
   writeln(invert(arg));
}

The enforce is needed because args[1] is user input. If the programmer
controlled the value of arg and believes arg != 0 always holds then no
enforce would be needed.

Doesn't this make sense?


Yes and no.  Yes, the ultimate result of what you wrote is the desired  
functionality.  But no, I don't think you have properly solved the problem.


Consider that user data, or environment data, can come from anywhere, and  
at any time.  Consider also that you have decoupled the function parameter  
validation from the function itself!  Ideally, invert should be the one  
deciding whether the original data is valid or not.  In order to write  
correct code, I must know what the contents of invert are as the writer  
of main.  I'd rather do something like:


int main(string[] args)
{
   auto argToInvert = to!double(args[1]);
   validateInvertArgs(argToInvert); // uses enforce
   invert(argToInvert);
}

Note that even *this* isn't ideal, because now the author of invert has to  
write and maintain a separate function for validating its arguments, even  
though invert is *already* validating its arguments.


It's almost as if, I want to re-use the same code inside invert that  
validates its arguments, but use a different mechanism to flag an error,  
depending on the source of the arguments.


It can get even more tricky, if say a function has two parameters, and one  
is hard-coded and the other comes from user input.



PS
For the record, I think (like most) that Errors should like Exceptions
work with scope, etc. The only arguments against is the theoretical
possibility of causing more damage while cleaning up. I say theoretical
because there was no practical example given. It seems that it may cause
more damage but it does not need to. Of course, if damage happens it's
the programmers fault but it's also the programmer's fault if he does
not try to do a graceful shutdown, i.e. closing sockets, sending a crash
report, or similar.


Indeed, it's all up to the programmer to handle the situation properly.   
If an assert occurs, the program may be already in an invalid state, and  
*trying to save* files or close/flush databases may corrupt the data.


My point is, it's impossible for the runtime to know that your code is  
properly handling the error or not, and that running all the finally/scope  
blocks will not be worse than not doing it.


-Steve


Re: Exception/Error division in D

2012-05-30 Thread Jens Mueller
Steven Schveighoffer wrote:
 On Wed, 30 May 2012 11:47:34 -0400, Jens Mueller
 jens.k.muel...@gmx.de wrote:
 
 Steven Schveighoffer wrote:
 
 case 2:
 
 int main(string[] args)
 {
writeln(invert(to!double(args[1])); // clearly a catchable error
 }
 
 This should be
 int main(string[] args)
 {
auto arg = to!double(args[1]);
enforce(arg != 0);
writeln(invert(arg));
 }
 
 The enforce is needed because args[1] is user input. If the programmer
 controlled the value of arg and believes arg != 0 always holds then no
 enforce would be needed.
 
 Doesn't this make sense?
 
 Yes and no.  Yes, the ultimate result of what you wrote is the
 desired functionality.  But no, I don't think you have properly
 solved the problem.
 
 Consider that user data, or environment data, can come from
 anywhere, and at any time.  Consider also that you have decoupled
 the function parameter validation from the function itself!
 Ideally, invert should be the one deciding whether the original data
 is valid or not.  In order to write correct code, I must know what
 the contents of invert are as the writer of main.  I'd rather do
 something like:
 
 int main(string[] args)
 {
auto argToInvert = to!double(args[1]);
validateInvertArgs(argToInvert); // uses enforce
invert(argToInvert);
 }
 
 Note that even *this* isn't ideal, because now the author of invert
 has to write and maintain a separate function for validating its
 arguments, even though invert is *already* validating its arguments.
 
 It's almost as if, I want to re-use the same code inside invert that
 validates its arguments, but use a different mechanism to flag an
 error, depending on the source of the arguments.
 
 It can get even more tricky, if say a function has two parameters,
 and one is hard-coded and the other comes from user input.

Why should invert validate its arguments? invert just states if the
input has this and that property, then I will return the inverse of the
argument. And it makes sure that its assumptions actually hold. And
these assumption are that fundamental that failing to verify these is an
error.
Why should it do more than that? Actually, it can't do more than that
because it does not know what to do. Assuming the user passed 0 then
different recovery approaches are possible.

 PS
 For the record, I think (like most) that Errors should like Exceptions
 work with scope, etc. The only arguments against is the theoretical
 possibility of causing more damage while cleaning up. I say theoretical
 because there was no practical example given. It seems that it may cause
 more damage but it does not need to. Of course, if damage happens it's
 the programmers fault but it's also the programmer's fault if he does
 not try to do a graceful shutdown, i.e. closing sockets, sending a crash
 report, or similar.
 
 Indeed, it's all up to the programmer to handle the situation
 properly.  If an assert occurs, the program may be already in an
 invalid state, and *trying to save* files or close/flush databases
 may corrupt the data.
 
 My point is, it's impossible for the runtime to know that your code
 is properly handling the error or not, and that running all the
 finally/scope blocks will not be worse than not doing it.

I thought this is the only argument for not executing finally/scope
blocks. Because running these in case of an Error may actually be worse
than not running them. Not that we have an example of such code but
that's the theoretical issue brought up against executing finally/scope
in case of an Error.

Jens


Re: Exception/Error division in D

2012-05-30 Thread Jonathan M Davis
On Wednesday, May 30, 2012 15:28:22 Jacob Carlborg wrote:
 On 2012-05-30 12:59, Jonathan M Davis wrote:
  Yes, which is why it's better to have an Error thrown rather than a halt
  instruction be executed. But that doesn't mean that any attempt at cleanup
  is any more valid.
 
 If you're not supposed to be able to catch Errors then what's the
 difference?

You can catch them to print out additional information or whatever is useful 
to generate more information about the Error. In fact, just what the Error 
gives you is already more useful: message, file, line number, stack trace, etc. 
That alone makes an Error more useful than a halt instruction.

You can catch them to attempt explicit cleanup that absolutely must be done 
for whatever reason (with the knowledge that it's potentially dangerous to do 
that cleanup due to the Error).

You can catch them in very controlled circumstances where you know that 
continuing is safe (obviously this isn't the sort of thing that you do in 
@safe code). For instance, in some restricted cases, that could be done with 
an OutOfMemoryError. But when you do that sort of thing you have to catch the 
Error _very_ close to the throw point and be sure that there's no cleanup code 
in between. It only works when you can guarantee yourself that the program 
state is not being compromised by the Error, and you're able to guarantee that 
continuing from the catch point is safe. That works in some cases with 
AssertError in unit test code but becomes problematic as such code becomes 
more complex.

- Jonathan M Davis


Re: Exception/Error division in D

2012-05-30 Thread Jonathan M Davis
On Wednesday, May 30, 2012 17:29:30 Don Clugston wrote:
 On 30/05/12 12:59, Jonathan M Davis wrote:
  On Wednesday, May 30, 2012 11:32:00 Don Clugston wrote:
  On 30/05/12 10:40, Jonathan M Davis wrote:
  On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:
  The fact that error don't trigger scope and everything is nonsensial.
  
  If an Error is truly unrecoverable (as they're generally supposed to
  be),
  then what does it matter? Something fatal occured in your program, so it
  terminates. Because it's an Error, you can get a stack trace and report
  something before the program actually terminates, but continuing
  execution after an Error is considered to be truly _bad_ idea, so in
  general, why does it matter whether scope statements, finally blocks, or
  destructors get executed? It's only rarer cases where you're trying to
  do
  something like create a unit test framework on top of assert that you
  would need to catch an Error, and that's questionable enough as it is.
  In
  normal program execution, an error is fatal, so cleanup is irrelevant
  and
  even potentially dangerous, because your program is already in an
  invalid
  state.
  
  That's true for things like segfaults, but in the case of an
  AssertError, there's no reason to believe that cleanup would cause any
  damage.
  In fact, generally, the point of an AssertError is to prevent the
  program from entering an invalid state.
  
  An assertion failure really isn't all that different from a segfault. By
  definition, if an assertion fails, the program is an invalid state,
  because the whole point of the assertion is to guarantee something about
  the program's state.
 
 There's a big difference. A segfault is a machine error. The integrity
 of the machine model has been violated, and the machine is in an
 out-of-control state. In particular, the stack may be corrupted, so
 stack unwinding may not be successful.
 
 But, in an assert error, the machine is completely intact; the error is
 at a higher level, which does not interfere with stack unwinding.
 
 Damage is possible only if you've written your destructors/finally code
 extremely poorly. Note that, unlike C++, it's OK to throw a new Error or
 Exception from inside a destructor.
 But with (say) a stack overflow, you don't necessarily know what code is
 being executed. It could do anything.

There is definitely a difference in severity. Clearly memory corruption is more 
severe than a logic error in your code. However, in the general case, if you 
have a logic error in your code which is caught by an assertion, there's no 
way to know without actually examining the code how valid the state of the 
program is at that point. It's in an invalid state _by definition_, because the 
assertion was testing the validity of the state of the program, and it failed. 
So, at that point, it's only a question of degree. _How_ invalid is the state? 
Since there's no way for the program to know how severe the logic error was, 
it has no way of knowing whether it's safe to run any cleanup code (the same 
as the program has no way of knowing whether a segfault is relatively minor - 
e.g. a null pointer - or absolutely catastrophic - e.g. memory is horribly 
corrupted).

If you got an OutOfMemoryError rather than one specifically indicating a logic 
error (as with Errors such as AssertError or RangeError), then that's 
specifcally telling you that your program has run out of a particular resource 
(i.e. memory), which means that any code which assumes that that resource is 
available (which in the case of memory is pretty much all code) will fail. 
Running cleanup code could be very precarious at that point if it allocates 
any memory (which a lot of cleanup code wouldn't, but I'm sure that it would 
be very easy to find cleanup code which did). Any further attempts at 
allocation would result in more OutOfMemoryErrors and leaving the cleanup code 
only partially run, thereby possibly making things even worse, depending on 
what the cleanup code does.

Running cleanup code is _not_ safe when an Error is thrown, because the 
program is definitely in an invalid state at that point, even if it's not as 
bad as a segfault can be.

Now, it may be that that risk is worth it, especially since a lot of the time, 
cleanup code won't be invalidated in the least by whatever caused Errors 
elsewhere in the program, and there are definitely plenty of cases where at 
least attempting to cleanup everything is better than skipping it all due of 
an Error somewhere else in the program. But it's still not safe. It's a 
question of whether we think that the risks posed by trying to run cleanup 
code after the program is in an invalid enough state that an Error was thrown 
are too great to attempt cleanup or whether we think that the problems caused 
by skipping that cleanup are greater.

  Now, if a segfault occurs (particularly if it's caused by something
  other than a null pointer), the program is likely to be 

Re: Exception/Error division in D

2012-05-30 Thread deadalnix

Le 30/05/2012 17:29, Don Clugston a écrit :

There's a big difference. A segfault is a machine error. The integrity
of the machine model has been violated, and the machine is in an
out-of-control state. In particular, the stack may be corrupted, so
stack unwinding may not be successful.

But, in an assert error, the machine is completely intact; the error is
at a higher level, which does not interfere with stack unwinding.

Damage is possible only if you've written your destructors/finally code
extremely poorly. Note that, unlike C++, it's OK to throw a new Error or
Exception from inside a destructor.
But with (say) a stack overflow, you don't necessarily know what code is
being executed. It could do anything.



Most segfault are null deference or unintizialized pointer deference. 
Both are recoverable.


Re: Exception/Error division in D

2012-05-30 Thread Jonathan M Davis
On Thursday, May 31, 2012 00:01:16 deadalnix wrote:
 Le 30/05/2012 17:29, Don Clugston a écrit :
  There's a big difference. A segfault is a machine error. The integrity
  of the machine model has been violated, and the machine is in an
  out-of-control state. In particular, the stack may be corrupted, so
  stack unwinding may not be successful.
  
  But, in an assert error, the machine is completely intact; the error is
  at a higher level, which does not interfere with stack unwinding.
  
  Damage is possible only if you've written your destructors/finally code
  extremely poorly. Note that, unlike C++, it's OK to throw a new Error or
  Exception from inside a destructor.
  But with (say) a stack overflow, you don't necessarily know what code is
  being executed. It could do anything.
 
 Most segfault are null deference or unintizialized pointer deference.
 Both are recoverable.

If you dereferenced a null pointer, it's a bug in your code. Your code is 
assuming that the pointer was non-null, which was obviously incorrect, because 
it was null. That's _not_ recoverable in the general case. Your code was 
obviously written with the assumption that the pointer was non-null, so your 
code is wrong, and so continuing to execute it makes no sense, because it's in 
an invalid state and could do who-knows-what. If there's any possibility of a 
pointer being null, the correct thing to do is to check it before 
dereferencing it. If you don't, it's bug.

Now, it's perfectly possible to design code which never checks for null 
pointers and if a null pointer is dereferenced throws an Exception and 
attempts to recover from it (assuming that it's possible to detect the 
dereference and throw at that point, which AFAIK is impossible with segfaults 
- maybe it could be done on Windows with its Access Violations, but segfaults 
trigger a signal handler, and you're screwed at that point). But writing code 
which just assumes that pointers are non-null and will throw if they are null 
is incredibly sloppy. It means that you're treating pointers like you'd treat 
user input rather than as part of your code.

- Jonathan M Davis


Re: Exception/Error division in D

2012-05-30 Thread Kapps

On Wednesday, 30 May 2012 at 22:22:01 UTC, Jonathan M Davis wrote:

On Thursday, May 31, 2012 00:01:16 deadalnix wrote:
Most segfault are null deference or unintizialized pointer 
deference.

Both are recoverable.


If you dereferenced a null pointer, it's a bug in your code. 
Your code is
assuming that the pointer was non-null, which was obviously 
incorrect, because
it was null. That's _not_ recoverable in the general case. Your 
code was
obviously written with the assumption that the pointer was 
non-null, so your
code is wrong, and so continuing to execute it makes no sense, 
because it's in
an invalid state and could do who-knows-what. If there's any 
possibility of a
pointer being null, the correct thing to do is to check it 
before

dereferencing it. If you don't, it's bug.

Now, it's perfectly possible to design code which never checks 
for null
pointers and if a null pointer is dereferenced throws an 
Exception and
attempts to recover from it (assuming that it's possible to 
detect the
dereference and throw at that point, which AFAIK is impossible 
with segfaults
- maybe it could be done on Windows with its Access Violations, 
but segfaults
trigger a signal handler, and you're screwed at that point). 
But writing code
which just assumes that pointers are non-null and will throw if 
they are null
is incredibly sloppy. It means that you're treating pointers 
like you'd treat

user input rather than as part of your code.

- Jonathan M Davis


All code has bugs in it. It's nice being notified about it and 
all, but if you release a server application, and it crashes 
every single time it encounters any bug... well, your customers 
will not have a fun time.




Re: Exception/Error division in D

2012-05-30 Thread Kapps

On Thursday, 31 May 2012 at 00:58:42 UTC, Kapps wrote:


All code has bugs in it. It's nice being notified about it and 
all, but if you release a server application, and it crashes 
every single time it encounters any bug... well, your customers 
will not have a fun time.


Note that this assumes you're in a part of code where you can 
isolate and revert anything the error may cause. Roll back a 
database transaction, disconnect a client, abort their web page 
request, etc.


Re: Exception/Error division in D

2012-05-30 Thread Artur Skawina
On 05/31/12 00:21, Jonathan M Davis wrote:
 Now, it's perfectly possible to design code which never checks for null 
 pointers and if a null pointer is dereferenced throws an Exception and 
 attempts to recover from it (assuming that it's possible to detect the 
 dereference and throw at that point, which AFAIK is impossible with segfaults 
 - maybe it could be done on Windows with its Access Violations, but segfaults 
 trigger a signal handler, and you're screwed at that point). But writing code 

No, it's easily recoverable. That does not mean however that it would be a good
idea to map segfaults to exceptions as a language feature. And dereferencing a
null pointer is *not* guaranteed to trap, all you need is a large enough offset
and you will get silent data corruption.

   int i = 42;
   auto j = cast(size_t)i;

   ubyte* p = null;
   p[j] = 13;
   assert(i!=42); // oops

artur


Re: Exception/Error division in D

2012-05-30 Thread Sean Kelly
On May 30, 2012, at 5:58 PM, Kapps opantm2+s...@gmail.com wrote:

 On Wednesday, 30 May 2012 at 22:22:01 UTC, Jonathan M Davis wrote:
 On Thursday, May 31, 2012 00:01:16 deadalnix wrote:
 Most segfault are null deference or unintizialized pointer deference.
 Both are recoverable.
 
 If you dereferenced a null pointer, it's a bug in your code. Your code is
 assuming that the pointer was non-null, which was obviously incorrect, 
 because
 it was null. That's _not_ recoverable in the general case. Your code was
 obviously written with the assumption that the pointer was non-null, so your
 code is wrong, and so continuing to execute it makes no sense, because it's 
 in
 an invalid state and could do who-knows-what. If there's any possibility of a
 pointer being null, the correct thing to do is to check it before
 dereferencing it. If you don't, it's bug.
 
 Now, it's perfectly possible to design code which never checks for null
 pointers and if a null pointer is dereferenced throws an Exception and
 attempts to recover from it (assuming that it's possible to detect the
 dereference and throw at that point, which AFAIK is impossible with segfaults
 - maybe it could be done on Windows with its Access Violations, but segfaults
 trigger a signal handler, and you're screwed at that point). But writing code
 which just assumes that pointers are non-null and will throw if they are null
 is incredibly sloppy. It means that you're treating pointers like you'd treat
 user input rather than as part of your code.
 
 - Jonathan M Davis
 
 All code has bugs in it. It's nice being notified about it and all, but if 
 you release a server application, and it crashes every single time it 
 encounters any bug... well, your customers will not have a fun time.

It's worth noting that Google apps abort on error. For server apps, a process 
crash is often designed to be invisible to the client, as much to allow 
seamless code upgrades as anything. 

Re: Exception/Error division in D

2012-05-30 Thread Walter Bright

On 5/30/2012 5:58 PM, Kapps wrote:

All code has bugs in it. It's nice being notified about it and all, but if you
release a server application, and it crashes every single time it encounters any
bug... well, your customers will not have a fun time.


The correct response to a server app crashing is to restart it, not attempt to 
keep a program in an invalid state running.


Attempting to continue normal operation of a program that has entered an invalid 
state is bad news from front to back. It is wrong wrong wrong wrong.




Re: Exception/Error division in D

2012-05-30 Thread Walter Bright

On 5/30/2012 2:32 AM, Don Clugston wrote:

In fact, generally, the point of an AssertError is to prevent the program from
entering an invalid state.


It's already in an invalid state when the assert fails, by definition.

It is not recoverable. The only option is a more or less graceful shutdown.


Re: Exception/Error division in D

2012-05-30 Thread Walter Bright

On 5/30/2012 8:05 AM, Steven Schveighoffer wrote:

I'd classify errors/exceptions into three categories:

1. corruption/segfault -- not recoverable under any reasonable circumstances.
Special cases exist (such as a custom paging mechanism).
2. program invariant errors (i.e. assert errors) -- Recovery is not defined by
the runtime, so you must do it manually. Any decision the runtime makes will be
arbitrary, and could be wrong.
3. try/catch exceptions -- these are planned for and *expected* to occur because
the program cannot control it's environment. e.g. EOF when none was expected.



A recoverable exception is NOT a logic bug in your program, which is why it is 
recoverable.


If there is recovery possible from a particular assert error, then you are using 
asserts incorrectly. Assert errors occur because your program has entered an 
unanticipated, invalid state. There's no such thing as knowing how to put it 
back into a valid state, because you don't know where it went wrong and how much 
is corrupted, etc.


Re: Exception/Error division in D

2012-05-29 Thread Sean Kelly
On May 24, 2012, at 11:50 PM, Jacob Carlborg wrote:

 On 2012-05-24 21:33, Sean Kelly wrote:
 
 This is a good point.  OutOfMemory conditions aside, the only time I'd want 
 to recover from an Error condition was at the point the event occurred, not 
 somewhere up the stack.
 
 You never feel you want to catch at the top level, print a sensible error 
 message and then exit the application? Instead of the application just 
 disappearing for user.

Well sure, but I wouldn't consider this recovery.

Re: Exception/Error division in D

2012-05-25 Thread Jacob Carlborg

On 2012-05-24 21:33, Sean Kelly wrote:


This is a good point.  OutOfMemory conditions aside, the only time I'd want to 
recover from an Error condition was at the point the event occurred, not 
somewhere up the stack.


You never feel you want to catch at the top level, print a sensible 
error message and then exit the application? Instead of the application 
just disappearing for user.


If the application can't print the error message it just fails in the 
same way as if you had not catch the error.


--
/Jacob Carlborg


Re: Exception/Error division in D

2012-05-24 Thread Sean Kelly
On May 24, 2012, at 3:27 AM, Denis Shelomovskij wrote:

 Let's talk about an abstract situation without caring about breaking existing 
 code, current docs, implementation etc.
 
 Definitions:
 * an Exception is something that tigers scope guards and executes 
 catch/finally blocks if thrown;
 * an Error is something that doesn't do it.
 
 As a result _we can't do any clean-up if an Error is thrown_ because scope 
 guards and catch/finally blocks aren't executed and the program is in invalid 
 state because of this. Of course it's theoretically possible to code without 
 scope guards and catch/finally blocks but isn't applicably for a real 
 project. E.g. in some editor if and Error is thrown there is no ability to 
 save opened documents.
 
 
 Main Question: What do you think can be an Error?
 
 Can Integer Divide by Zero be an Error? Definitely, not.
 
 Can Access Violation be an Error? No, because it's very common to access a 
 field/virtual member function of a null object.
 
 Can Out of memory be an Error? No, because e.g. if I read a user file that 
 require me to create a large array ( 100 MiB, e.g.) I don't want to crash, 
 but just tell, that Dear user, the file can't be opened because it 
 requires...
 
 
 So what am I think can be an Error? IMHO, nothing. Because throwing 
 everything can indicate that program in very good/terribly bad state and 
 compiler doesn't know anything about that. And because fatal error is fatal 
 the program should just try to print error and close instead of throwing 
 something.

I agree.  However, the benefit to having Error is so that nothrow can exist.  
If every exception were considered recoverable then we'd have to throw out 
nothrow as well, since basically anything can generate an access violation, for 
example.  Or we could weaken nothrow so that it didn't even allow memory 
allocations, which would render it largely useless.  For what it's worth, the D 
runtime does do clean-up for both Errors and Exceptions today.  The only 
difference is codgen for scope statements and such inside nothrow 
functions--instead of being rewritten as try/finally the on-exit code is just 
inserted at the proper scope exit points.


 Let's now return to the real D world. Current implementation treats Errors as 
 Exceptions for now. Documentation keeps silence. All listed can't be an 
 error cases are Errors (and it's terrible).
 
 So why do we has Exception/Error division in D? Because of nothrow. 
 Personally I don't need nothrow for that high cost of making D unusable for 
 me. Lets realize and solve Exception/Error problem and solve nothrow in the 
 second place.

Seems you already know this.  Oops.  I'm inclined to agree, personally.  
nothrow is less useful in D than in C++ because it's safe to throw from dtors 
in D (problems related to throwing from a finalizer during a GC collection 
aside--that's more an exception safety issue for the GC than anything else).

Re: Exception/Error division in D

2012-05-24 Thread Gor Gyolchanyan
I'd say, removing nothrow and Error from D would be a good idea. Everybody
throws Exception from anywhere. What would be the practical reason not to
do that (besides potentially breaking code)?

On Thu, May 24, 2012 at 9:51 PM, Sean Kelly s...@invisibleduck.org wrote:

 On May 24, 2012, at 3:27 AM, Denis Shelomovskij wrote:

  Let's talk about an abstract situation without caring about breaking
 existing code, current docs, implementation etc.
 
  Definitions:
  * an Exception is something that tigers scope guards and executes
 catch/finally blocks if thrown;
  * an Error is something that doesn't do it.
 
  As a result _we can't do any clean-up if an Error is thrown_ because
 scope guards and catch/finally blocks aren't executed and the program is in
 invalid state because of this. Of course it's theoretically possible to
 code without scope guards and catch/finally blocks but isn't applicably for
 a real project. E.g. in some editor if and Error is thrown there is no
 ability to save opened documents.
 
 
  Main Question: What do you think can be an Error?
 
  Can Integer Divide by Zero be an Error? Definitely, not.
 
  Can Access Violation be an Error? No, because it's very common to
 access a field/virtual member function of a null object.
 
  Can Out of memory be an Error? No, because e.g. if I read a user file
 that require me to create a large array ( 100 MiB, e.g.) I don't want to
 crash, but just tell, that Dear user, the file can't be opened because it
 requires...
 
 
  So what am I think can be an Error? IMHO, nothing. Because throwing
 everything can indicate that program in very good/terribly bad state and
 compiler doesn't know anything about that. And because fatal error is fatal
 the program should just try to print error and close instead of throwing
 something.

 I agree.  However, the benefit to having Error is so that nothrow can
 exist.  If every exception were considered recoverable then we'd have to
 throw out nothrow as well, since basically anything can generate an access
 violation, for example.  Or we could weaken nothrow so that it didn't even
 allow memory allocations, which would render it largely useless.  For what
 it's worth, the D runtime does do clean-up for both Errors and Exceptions
 today.  The only difference is codgen for scope statements and such inside
 nothrow functions--instead of being rewritten as try/finally the on-exit
 code is just inserted at the proper scope exit points.


  Let's now return to the real D world. Current implementation treats
 Errors as Exceptions for now. Documentation keeps silence. All listed
 can't be an error cases are Errors (and it's terrible).
 
  So why do we has Exception/Error division in D? Because of nothrow.
 Personally I don't need nothrow for that high cost of making D unusable for
 me. Lets realize and solve Exception/Error problem and solve nothrow in the
 second place.

 Seems you already know this.  Oops.  I'm inclined to agree, personally.
  nothrow is less useful in D than in C++ because it's safe to throw from
 dtors in D (problems related to throwing from a finalizer during a GC
 collection aside--that's more an exception safety issue for the GC than
 anything else).




-- 
Bye,
Gor Gyolchanyan.


Re: Exception/Error division in D

2012-05-24 Thread Steven Schveighoffer
On Thu, 24 May 2012 06:27:12 -0400, Denis Shelomovskij  
verylonglogin@gmail.com wrote:


Let's talk about an abstract situation without caring about breaking  
existing code, current docs, implementation etc.


Definitions:
* an Exception is something that tigers scope guards and executes  
catch/finally blocks if thrown;

* an Error is something that doesn't do it.


I'll give you a different definition:

* an Exception is something that can be handled far away from the context  
of the error, because the system can safely unwind the stack.
* an Error must be handled at the point the error occurred, or the program  
state is by definition invalid.




As a result _we can't do any clean-up if an Error is thrown_ because  
scope guards and catch/finally blocks aren't executed and the program is  
in invalid state because of this. Of course it's theoretically possible  
to code without scope guards and catch/finally blocks but isn't  
applicably for a real project. E.g. in some editor if and Error is  
thrown there is no ability to save opened documents.



Main Question: What do you think can be an Error?

Can Integer Divide by Zero be an Error? Definitely, not.


I agree with you there.  However, the problem isn't nearly as bad as you  
say.  The runtime doesn't actually deal with SIGFPE on Unix based systems,  
and most places where an Error is thrown, it's within asserts, which are  
compiled out in release code.


If you get one of these, you can handle the signal.  I think on Windows  
it's handled for you, but there should be a way to intercept this and do  
recovery.


Can Access Violation be an Error? No, because it's very common to  
access a field/virtual member function of a null object.


I'd argue this is unrecoverable.  Access Violation results from  
corruption, and the damage has already been done.  Even a null pointer  
access can be the cause of previous corruption.  There is no recovery  
from memory corruption.  There is no way to plan for it.


Now, if you want to handle it specifically for your program, that should  
be doable, at your own risk.  But there's no way throwing an Exception is  
a valid result.


Can Out of memory be an Error? No, because e.g. if I read a user file  
that require me to create a large array ( 100 MiB, e.g.) I don't want  
to crash, but just tell, that Dear user, the file can't be opened  
because it requires...


Right, out of memory is only an error if your program's invariant depends  
on the memory allocation.  You can plan for the above easily enough, but  
not realistically for all tasks and all library code that require  
allocation.


For example, let's say you are restructuring a hash table, and you  
reallocate some nodes.  You have half transferred over the old structure  
to the new structure, and you run out of memory.  How to recover from this?


In summary, I think we can adjust Windows divide by zero errors to allow  
you to handle them manually, the Posix version is fine (no Error is  
generated), access violations are unequivocally Errors, and out of memory  
should be fixable by making allocation routines that do not throw (just  
return null).


An interesting idea would be to allow a global handler for all errors.   
So if you throw an Exception, it unwinds the stack like normal.  If you  
throw an Error, it checks a handler to see if you want to handle that  
error (via registering a function/delegate), and if not handled throws  
Error without properly unwinding the stack.


-Steve


Re: Exception/Error division in D

2012-05-24 Thread Sean Kelly
On May 24, 2012, at 11:39 AM, Steven Schveighoffer wrote:

 On Thu, 24 May 2012 06:27:12 -0400, Denis Shelomovskij 
 verylonglogin@gmail.com wrote:
 
 Let's talk about an abstract situation without caring about breaking 
 existing code, current docs, implementation etc.
 
 Definitions:
 * an Exception is something that tigers scope guards and executes 
 catch/finally blocks if thrown;
 * an Error is something that doesn't do it.
 
 I'll give you a different definition:
 
 * an Exception is something that can be handled far away from the context of 
 the error, because the system can safely unwind the stack.
 * an Error must be handled at the point the error occurred, or the program 
 state is by definition invalid.

This is a good point.  OutOfMemory conditions aside, the only time I'd want to 
recover from an Error condition was at the point the event occurred, not 
somewhere up the stack.


 Can Access Violation be an Error? No, because it's very common to access a 
 field/virtual member function of a null object.
 
 I'd argue this is unrecoverable.  Access Violation results from corruption, 
 and the damage has already been done.  Even a null pointer access can be the 
 cause of previous corruption.  There is no recovery from memory corruption. 
  There is no way to plan for it.
 
 Now, if you want to handle it specifically for your program, that should be 
 doable, at your own risk.  But there's no way throwing an Exception is a 
 valid result.

Right.  Recovery is potentially valid at the point of failure, not somewhere up 
the stack.


 Can Out of memory be an Error? No, because e.g. if I read a user file that 
 require me to create a large array ( 100 MiB, e.g.) I don't want to crash, 
 but just tell, that Dear user, the file can't be opened because it 
 requires...
 
 Right, out of memory is only an error if your program's invariant depends on 
 the memory allocation.  You can plan for the above easily enough, but not 
 realistically for all tasks and all library code that require allocation.
 
 For example, let's say you are restructuring a hash table, and you reallocate 
 some nodes.  You have half transferred over the old structure to the new 
 structure, and you run out of memory.  How to recover from this?

I think it's fair to expect code that allocates be exception-safe in the face 
of allocation errors.  I know I'm always very careful with containers so that 
an allocation failure doesn't result in corruption, for example.


 In summary, I think we can adjust Windows divide by zero errors to allow you 
 to handle them manually, the Posix version is fine (no Error is generated), 
 access violations are unequivocally Errors, and out of memory should be 
 fixable by making allocation routines that do not throw (just return null).

It would be kind of cool if there were some sort of unified way to handle 
system-generated errors, though I don't know that this is practical.  signals 
sort of work on Windows, but I'm pretty sure the contextual sigaction stuff 
does not.


 An interesting idea would be to allow a global handler for all errors.  So 
 if you throw an Exception, it unwinds the stack like normal.  If you throw an 
 Error, it checks a handler to see if you want to handle that error (via 
 registering a function/delegate), and if not handled throws Error without 
 properly unwinding the stack.

^^ this

Re: Exception/Error division in D

2012-05-24 Thread Steven Schveighoffer
On Thu, 24 May 2012 15:33:07 -0400, Sean Kelly s...@invisibleduck.org  
wrote:



On May 24, 2012, at 11:39 AM, Steven Schveighoffer wrote:



Can Out of memory be an Error? No, because e.g. if I read a user  
file that require me to create a large array ( 100 MiB, e.g.) I don't  
want to crash, but just tell, that Dear user, the file can't be  
opened because it requires...


Right, out of memory is only an error if your program's invariant  
depends on the memory allocation.  You can plan for the above easily  
enough, but not realistically for all tasks and all library code that  
require allocation.


For example, let's say you are restructuring a hash table, and you  
reallocate some nodes.  You have half transferred over the old  
structure to the new structure, and you run out of memory.  How to  
recover from this?


I think it's fair to expect code that allocates be exception-safe in the  
face of allocation errors.  I know I'm always very careful with  
containers so that an allocation failure doesn't result in corruption,  
for example.


I don't think it's fair to expect *all* code to be able to safely recover  
from an out of memory exception.  I pretty much *never* write code that  
worries about out of memory errors.  One cannot always expect an operation  
involving hundreds of allocations to be atomic.


That being said, we should provide a mechanism so you can handle it, as  
it's reliably detectable and very recoverable in many situations.


-Steve