Comparing Exceptions and Errors
Ola Fosheim Grøstad
ola.fosheim.grostad at gmail.com
Sun Jun 5 16:27:07 UTC 2022
Ok, so I am a bit confused about what is Error and what is not…
According to core.exception there is wide array of runtime Errors:
```
RangeError
ArrayIndexError
ArraySliceError
AssertError
FinalizeError
OutOfMemoryError
InvalidMemoryOperationError
ForkError
SwitchError
```
I am not sure that any of these should terminate anything outside
the offending actor, but I could be wrong as it is hard to tell
exactly when some of those are thrown.
InvalidMemoryOperationError sound bad, of course, but the docs
says «An invalid memory operation error occurs in circumstances
when the garbage collector has detected an operation it cannot
reliably handle. The default D GC is not re-entrant, so this can
happen due to allocations done from within finalizers called
during a garbage collection cycle.»
This sounds more like an issue that needs fixing…
On Sunday, 5 June 2022 at 14:24:39 UTC, Ali Çehreli wrote:
> The code is written in a way that both arrays will *always*
> have equal number of elements. And there is a "silly" check for
> that invariant. So far so good. The issue is what to do *when*
> that assert fails.
>
> Are you sure that it was a silly programmer mistake? I am not
> sure at all.
Ok, so this is a question of the layers:
```
-------- top layer ------
D | E
|
----- middle layer ------
B | C
|
|
---- bottom layer -------
A
````
If the failed assert is happening in a lower layer A then code on
the outer layer should fault (or roll back a transaction).
Whether it is reasonable to capture that error and suppress it
depends on how independent you want those layers to be in your
architecture. It also depends on the nature of layer A.
If the failed assert happens in middle layer section B, then the
D would be affected, but not A, C or E.
The key issue is that the nature of layers is informal in the
language (in fact, in most languages, a weakness), so only the
programmer can tell what is reasonable or not.
In fact, when we think about it; most aspects about what is
expected from a program is informal… so it is very difficult to
make judgment at the compiler level.
> Is the only other culprit the runtime kernel? I really don't
> know who else may be involved.
I mean the application's «custom actor kernel», a hardened piece
of code that is not modified frequently and heavily tested. The
goal is to keep uncertainty local to an actor so that you can
toss out misbehaving actors and keep the rest of the system
working smoothly (99.5% of the time, 50 minutes downtime per
week).
Actors are expected to contain bugs because the game system is
continuously modified (to balance the game play, to get new
content, more excitement, whatever…). This is why we want 100%
@safe code as a feature.
> There are also bugs in unrelated actor code writing over each
> others' memory.
But that cannot happen if I decide to make actors 100% @safe and
only let them interact with each other through my «custom actor
kernel»?
> You are free to choose to catch Errors and continue under the
> assumption that it is safe to do so.
Now I am confused!! Steven wrote «I've thought in the past that
throwing an error really should not throw, but log the error
(including the call stack), and then exit without even attempting
to unwind the stack.»
Surely, the perspective being promoted is to make sure that
Errors cannot be stopped from propagating? That is why this
becomes a discussion?
If an Error can propagate through "nothrow" then the compiler
should emit handler code for it and issue a warning. If you don't
want that then the programmer should safe guard against it,
meaning: manually catch and abort or do manual checks in all
locations above it where Errors can arise. The compiler knows
where.
Not really sure why D has "nothrow", it doesn't really fit with
the rest of the language? To interface with C++ perhaps?? If that
is the case, just adopt C++ "noexcept" semantics, use assert()
for debugging only, in "nothrow" code. And discourage the use of
"nothrow". Heck, throw in a compiler switch to turn off "nothrow"
if that is safe.
> The advice in the article still holds for me. I think the main
> difference is in the assumptions we make about an Errors: Is it
> a logic error in actor code or some crazy state that will cause
> weirder results if we continue. We can't know for sure.
And this is no different from other languages with a runtime. You
cannot be sure, but it probably isn't a runtime issue, and even
if it was… players will be more upset by not being able to play
than to have some weird effects happening. Same for chat service.
Same for being able to read Wikipedia-caches (worse to have no
access than to have 1% of pages garbled on display until the
server is updated).
Different settings need different solutions. So, maybe
interfacing with C++ requires "nothrow", but if that is the only
reason… why let everybody pay a price for it?
(I use "noexcept" in my C++ code, but that is more an act of
documentation, and that clearly falls apart in D with Error.)
More information about the Digitalmars-d-learn
mailing list