proj-oot-ootErrorThoughts

--

also, keep in mind:

http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors/ http://blog.ezyang.com/2011/08/8-ways-to-report-errors-in-haskell-revisited/ http://book.realworldhaskell.org/read/error-handling.html

am i making 'nil' into some sort of alternate Exception type? If so, maybe we should just merge it with proper Exceptions. And remember, i still want to have apostrophes converting between Maybe/Option types, Exceptions, nullable types, etc.


Syntax encouraging extensible exception handling

When someone is testing to see if an exception is of a certain type, the syntax should encourage them to do a test that later allows other types of exceptions to register as 'true' in that test via something like subclasses (or rather, implmenting an interface). I'm thinking of just using the word 'is', eg:

"if exc is NotImplementedException?"

---

often you WANT strict evaluation on one function. Eg if you are about to call a side-effectful function, you may want to evaluate all of the inputs you are about to pass to it first so that if there is some error generated while evaluating one of those inputs, the side-effectful function never gets called, rather than having an exception in the middle of whatever it's doing (when some side-effects, but not all, may have already been emitted, leaving it in an inconsisent state)

---

some common classes/attributes of errors esp. for messages/requests/commands sent over a network:

some 'other' truth value suggestions from http://cicada3301.org/test/ :

also, https://en.wikipedia.org/wiki/Tetralemma and Belnap's relevance logic [1] suggests:

also, Kant has his negative vs. infinite judgement distinction.

also, https://en.wikipedia.org/wiki/Logical_quality also mentions some other alternative truth values:

https://en.wikipedia.org/wiki/Four-valued_logic further suggests for sensor readings:

https://en.wikipedia.org/wiki/IEEE_1164 's 9-valued logic:

i wrote this elsewhere: neither/maybe/unknown/other/decline to state/does no apply/the question is flawed

---

D's design by contact (DBC) features:

https://dlang.org/spec/contracts.html

---

This discussion on panicky vs. non-panicky APIs explains why the distinction between 'expected' errors (exceptions) and 'unexpected' errors (panics) can't be made; eg "what if you have an API that lets users send a list of image transformations, and the user requests a face-detect crop, followed by a fixed crop with a given x, y, w, h. Clearly your code can get out of (2D) array bounds with the fixed crop... Suddenly the thing that was "unexpected" at the array level becomes very much expected at the higher API level...So the API provider can't decide whether an error is expected or not. Only the API consumer can do that..... Which is why exceptions work the way they do: bubble until a consumer makes a decision, otherwise consider the whole error unexpected. " [3]

Someone responds, "Non-panicky APIs can be used in a panicky way via unwrap() or expect(). There are very few panicky APIs, reserved for things where 99% of the time you want it to panic and it would be annoying to have to handle errors all the time. Array indexing is one of these cases, where it would be super annoying to handle errors on each indexing operation. But if you're in a situation where you expect an index to fail, just use `get()` which returns an Option instead."

Someone else responds that the difference is really that some errors, in the process of being revealed, may corrupt the state: "Keep in mind that an out of bounds array access can cause a lot of problems; in the best case, it would cause a segfault, and in the worst it would allow for code injection. So there isn't really a case where accessing an array out of bounds makes sense. That's where the idea of "expected vs unexpected errors" comes from.". For Oot that's probably not an issue because since we don't care about performance in the default case, we probably just bounds check everything (mb we can have a special panic mode that only occurs if the user runs in some sort of high performance, no bounds checking mode, but that's not what we are optimizing for currently so i'm not going to think much about it right now).

I think in Oot we can probably just have one thing, exceptions. So, yes, every array index operation might throw an exception. Do we then have checked exceptions? Nah, let's assume by default that EVERYTHING might throw ANY exception... BUT something can OPTIONALLY declare their possibly-thrown-exceptions, which means that they won't throw anything else, and that is guaranteed by typechecking. So it's like gradual typing.

We should also have some syntactic sugar for 'catch any exception here, and then wrap it with an exception of type X, and then rethrow it'. And then also have some syntactic sugar for modules (or mb just for any lexical scope) that do that for every function in the module. So that it's easy for LibraryM? to wrap every uncaught OutOfBoundsException? generated from its code with a LibraryMException?, which has some field that contains the OutOfBoundsException?.

---

http://ashtonkemerling.com/blog/2017/01/26/java-without-if/ reminds us that we want Either, not Maybe (that is, you want to be able to say WHY something failed when the Maybe is a None). And i would add that we need to deal well with exception towers. (eg if f() calls g(), and g() raises an exception which is converted to None/Because-divide-by-zero-in-g, then f() should be able to add its own comment/reason wrapping this, so in total you have: error-in-f-while-trying-to-normalize(Because-divide-by-zero-in-g)

---

https://github.com/google/lmctfy/blob/master/util/task/codes.proto , of which "Inufu" said in [4] that "I've yet to encounter a case where these ~15 codes were insufficient", contains:

OK not an error CANCELLED operation was cancelled (typically by the caller). UNKNOWN unknown error INVALID_ARGUMENT arguments are problematic regardless of the state of the system (e.g., a malformed file name). DEADLINE_EXCEEDED NOT_FOUND ALREADY_EXISTS Some entity that we attempted to create (e.g., file or directory) already exists PERMISSION_DENIED RESOURCE_EXHAUSTED FAILED_PRECONDITION system is not currently in a state required for the operation's execution ABORTED typically due to a concurrency issue like sequencer check failures, transaction aborts. client should typically retry at a higher-level (e.g., restarting a read-modify-write sequence) OUT_OF_RANGE note: problem may be fixed if the system state change UNIMPLEMENTED INTERNAL internal error UNAVAILABLE client should typically retry with a backoff DATA_LOSS Unrecoverable data loss or corruption.

my note: of course we also need to include 'MAYBE_ERR', to cover the case where we didn't get a reply and we don't know if the operation succeeded (but the return message got lost), or failed, or was executed partially. As well as various others, eg OOM subtype of RESOURCE_EXHAUSTED, etc.

---

In [5], "Inufu" said e liked statusOr from [6]. E says "This uses a standardized set of error codes and a freeform string to indicate errors. ". statusOr appears to be an Either<Status, T> where the error side of the Either is of type Status, and the value side is of type T.

I don't think we should go that far (only having a standardized set of error codes and a freeform string), i think we should have an extensible hierarchy like Python, such that custom subclasses also may or may not carry data in addition to error message strings, but i like their error codes as classes in this hierarchy. And i like using a template Either with the left side constrained to be an Exception or Status or somesuch, and the right side being a value of the template class.

---