diff options
Diffstat (limited to 'docs/ERRORS.md')
-rw-r--r-- | docs/ERRORS.md | 83 |
1 files changed, 74 insertions, 9 deletions
diff --git a/docs/ERRORS.md b/docs/ERRORS.md index 4a4b206..a6e7a6a 100644 --- a/docs/ERRORS.md +++ b/docs/ERRORS.md @@ -1,24 +1,89 @@ # Error Handling -Error handling should perhaps be abstracted into a more general effects system. -But if not, then this document lays out some potential ideas. +Puck's error handling is shamelessly stolen from Swift. +It uses a combination of Option/Result types and try/catch/finally statements, and leans somewhat on Puck's metaprogramming capabilities. ---- +```puck +func get_debug[T](): T = + let value: Option[T] = self.unsafe_get(413) + try: + let value = value! + catch Exception(e) + + +try: + .. +catch: + .. +finally: + print "No such errors" +``` + +There are several ways to handle errors in Puck. If the error is encoded in the type, one can: +1. `match` on the error +2. compactly match on the error with `if ... of` +3. propagate the error with `?` +4. throw the error with `!` + +If an error is thrown, one must explicitly handle (or disregard) it with a `try/catch` block. +This method of error handling may feel more familiar to Java programmers. + +## Errors as monads + +Puck provides [`Option[T]`](std/default/options.pk) and a [`Result[T, E]`](std/default/results.pk) types, imported by default. These are `union` types and so must be pattern matched upon to be useful: but the standard library provides [a bevy of helper functions](std/default/results.pk). +Two in particular are of note. The `?` operator unwraps a Result or propagates its error up a function call (and may only be used in type-appropriate contexts). The `!` operator unwraps an Option or Result directly or throws an exception in the case of None or Error. ```puck +pub macro `?`[T, E](self: Result[T, E]) = + quote: + match `self` + of Okay(x): x + of Error(e): return Error(e) ``` -Puck provides [`Option[T]`](std/default/options.pk) and a [`Result[T, E]`](std/default/results.pk) types, imported by default. These are `union` types and so must be pattern matched upon to be useful: but the standard library provides a bevy of helper functions. +```puck +pub func `!`[T](self: Option[T]): T = + match self + of Some(x): x + of None: raise EmptyValue -Two in particular are of note. The `?` operator unwraps a Result or propagates its error up a function call. The `!` operator unwraps an Option or Result directly or throws an exception in the case of None or Error. +pub func `!`[T, E](self: Result[T, E]): T = + of Okay(x): x + of Error(e): raise e +``` + +The utility of the provided helpers in [`std.options`](std/default/options.pk) and [`std.results`](std/default/results.pk) should not be understated. While encoding errors into the type system may appear restrictive at first glance, some syntactic sugar goes a long way in writing compact and idiomatic code. Java programmers in particular are urged to give type-first errors a try, before falling back on unwraps and `try`/`catch`. + +A notable helpful type is the aliasing of `Result[T]` to `Result[T, ref Err]`, for when the particular error does not matter. This breaks `try`/`catch` exhaustion (as `ref Err` denotes a reference to *any* Error), but is particularly useful when used in conjunction with the propagation operator. + +## Errors as catchable exceptions + +Errors raised by `raise`/`throw` (or subsequently the `!` operator) must be explicitly caught and handled via a `try`/`catch`/`finally` statement. +If an exception is not handled within a function body, the function must be explicitly marked as a throwing function via the `yeet` prefix (name to be determined). The compiler will statically determine which exceptions in particular are thrown from any given function, and enforce them to be explicitly handled or explicitly ignored. + +Errors are types. An error thrown from an unwrapped `Result[T, E]` is of type `E`. `catch` statements, then, may pattern match upon possible errors, behaving similarly to `of` branches. ```puck +try: + ... +catch "Error": + ... +finally: + ... ``` -Errors raised by the `!` operator must be explicitly caught and handled via a `try/catch/finally` statement. +This creates a distinction between two types of error handling, working in sync: functional error handling with [Option](https://en.wikipedia.org/wiki/Option_type) and [Result](https://en.wikipedia.org/wiki/Result_type) types, and object-oriented error handling with [catchable exceptions](https://en.wikipedia.org/wiki/Exception_handling). These styles may be swapped between with minimal syntax overhead. Libraries, however, should universally use `Option`/`Result`, as this provides the best support for both styles. + +<!-- [nullable types](https://en.wikipedia.org/wiki/Nullable_type)?? --> + +## Unrecoverable exceptions -If an exception is not handled within a function body, the function must be explicitly marked as a throwing function via the `yeet` prefix (final name to be determined). The compiler will statically determine which exceptions in particular are thrown from any given function. +There exist errors from which a program can not reasonably recover. These are the following: +- `Assertation Failure`: a call to an `assert` function has returned false at runtime. +- `Out of Memory`: the executable is out of memory. +- `Stack Overflow`: the executable has overflowed the stack. +- any others? -This creates a distinction between two types of error handling, working in sync: functional error handling with [Option](https://en.wikipedia.org/wiki/Option_type) and [Result](https://en.wikipedia.org/wiki/Result_type) types, and object-oriented error handling with [nullable types](https://en.wikipedia.org/wiki/Nullable_type) and [exceptions](https://en.wikipedia.org/wiki/Exception_handling). These styles may be swapped between with minimal syntax overhead. Libraries, however, should universally use Options and Results, as this provides best for both usages. +They are not recoverable, but the user should be aware of them as possible failure conditions. -References: [std/options](std/default/options.pk), [std/results](std/default/results.pk), [Error Handling in Swift](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/errorhandling) (shamelessly stolen) +References: [Error Handling in Swift](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/errorhandling) |