Error
The Error
type works like a discriminated-union, it is an abstract record
type with many sub-cases
(which are listed below). It is used extensively with various monadic types, like Fin<A>
, the
Effect System monads of Eff<A>
, Eff<RT, A>
, Aff<A>
, Aff<RT, A>
and the compositional
streaming Pipes features.
The reason they're buried in the
Common
namespace is because,Error
is a common type name. And so, this gives the programmer a chance to not include it whenusing LanguageExt;
Error
exists because Exception
is really only meant for exceptional errors. However, in C#-land we've been trained
to throw them even for expected errors.
Instead we use Error
to represent three key types of error:
Exceptional
- An unexpected errorExpected
- An expected errorManyErrors
- Many errors (possibly zero)
These are the key base-types that indicate the 'flavour' of the error. For example, a 'user not found' error isn't
something exceptional, it's something we expect might happen. An OutOfMemoryException
however, is
exceptional - it should never happen, and we should treat it as such.
Most of the time we want sensible handling of expected errors, and bail out completely for something exceptional. We also want
to protect ourselves from information leakage. Leaking exceptional errors via public APIs is a surefire way to open up more
information to hackers than you would like. The Error
derived types all try to protect against this kind of leakage without
losing the context of the type of error thrown.
Essentially an error is either created from an Exception
or it isn't. This allows for expected errors to be
represented without throwing exceptions, but also it allows for more principled error handling. We can pattern-match on the
type, or use some of the built-in properties and methods to inspect the Error
:
IsExceptional
-true
for exceptional errors. ForManyErrors
this istrue
if any of the errors are exceptional.IsExpected
-true
for non-exceptional/expected errors. ForManyErrors
this istrue
if all of the errors are expected.Is<E>(E exception)
-true
if theError
is exceptional and any of the the internalException
values are of typeE
.Is(Error error)
-true
if theError
matches the one provided. i.e.error.Is(Errors.TimedOut)
.
The Error
type can be constructed to be exceptional or expected. For example, this is an expected error:
Error.New("This error was expected")
When expected errors are used with codes then equality and matching is done via the code only:
Error.New(404, "Page not found");
And this is an exceptional error:
try
{
// This wraps up the exceptional error
}
catch(Exception e)
{
return Error.New(e);
}
Finally, you can collect many errors:
Error.Many(Error.New("error one"), Error.New("error two"));
Or more simply:
Error.New("error one") + Error.New("error two")
You can extend the set of error types (perhaps for passing through extra data) by creating a new
record inherits Exceptional
or Expected
:
public record BespokeError(bool MyData)
: Expected("Something bespoke", 100, None);
By default the properties of the new error-type won't be serialised. So, if you want to pass a
payload over the wire, add the [property: DataMember]
attribute to each member:
public record BespokeError([property: DataMember] bool MyData)
: Expected("Something bespoke", 100, None);
Using this technique it's trivial to create new error-types when additional data needs to be moved around, but also there's a ton of built-in functionality for the most common use-cases.
- Error
- Code
- Message
- Inner
- Is <E> ()
- Is (Error error)
- IsExceptional
- IsExpected
- Head ()
- Tail ()
- IsEmpty
- Count
- ToException ()
- Exception
- ToErrorException ()
- Append (Error error)
- + (Error lhs, Error rhs)
- AsEnumerable ()
- ToString ()
- New (Exception thisException)
- New (string message, Exception thisException)
- New (string message)
- New (int code, string message)
- New (int code, string message, Error inner)
- New (string message, Error inner)
- Many (params Error[] errors)
- Many (Seq<Error> errors)
- FromObject (object value)
- Throw ()
- Expected (string Message, int Code, Option<Error> Inner = default)
- Exceptional (string Message, int Code)
- Message
- Code
- ToString ()
- Inner
- ToException ()
- ToErrorException ()
- Is <E> ()
- Is (Error error)
- IsExceptional
- IsExpected
- BottomError ()
- Default = new BottomError()
- Code
- Message
- ToString ()
- ToException ()
- ToErrorException ()
- Is <E> ()
- Is (Error error)
- IsExceptional
- IsExpected
- ManyErrors ([property: DataMember] Seq<Error> Errors)
- Code
- Message
- ToString ()
- ToException ()
- ToErrorException ()
- Is <E> ()
- Is (Error error)
- IsExceptional
- IsExpected
- Head ()
- Tail ()
- IsEmpty
- Count
- AsEnumerable ()
- ErrorException
- Code
- Inner
- ToError ()
- IsEmpty
- IsExceptional
- IsExpected
- Append (ErrorException error)
- + (ErrorException lhs, ErrorException rhs)
- GetEnumerator ()
- ToString ()
- New (Exception thisException)
- New (string message, Exception thisException)
- New (string message)
- New (int code, string message)
- New (int code, string message, ErrorException inner)
- New (string message, ErrorException inner)
- Many (params ErrorException[] errors)
- Many (Seq<ErrorException> errors)
- ExpectedException
- ExpectedException (string message, int code, Option<ErrorException> inner)
- Code
- Message
- Inner
- ToError ()
- IsExceptional
- IsExpected
- Append (ErrorException error)
- ExceptionalException
- ExceptionalException (Exception Exception)
- ExceptionalException (string Message, int Code)
- ExceptionalException (string Message, Exception Exception)
- Exception
- Code
- Message
- Inner
- ToError ()
- IsExceptional
- IsExpected
- Append (ErrorException error)
- ManyExceptions
- ManyExceptions (Seq<ErrorException> errors)
- Errors
- Code
- Message
- Inner
- ToError ()
- IsEmpty
- IsExceptional
- IsExpected
- Append (ErrorException error)
- GetEnumerator ()
- BottomException
- Errors
- None = new ManyErrors(Seq<Error>.Empty)
- BottomText = "In a bottom state and therefore cannot proceed. This can happen when an expression couldn't " + "evaluate to a value. This might be due to filter/where, or sometimes if a `struct` wasn't initialised " + "properly (i.e. via `default(T)` or an uninitialised member)."
- BottomCode = -2000000001
- Bottom = BottomError.Default
- CancelledText = "cancelled"
- CancelledCode = -2000000000
- Cancelled = (CancelledCode, CancelledText)
- TimedOutText = "timed out"
- TimedOutCode = -2000000002
- TimedOut = (TimedOutCode, TimedOutText)
- SequenceEmptyText = "sequence empty"
- SequenceEmptyCode = -2000000003
- SequenceEmpty = (SequenceEmptyCode, SequenceEmptyText)
- ClosedText = "closed"
- ClosedCode = -2000000004
- Closed = (ClosedCode, ClosedText)
- ParseErrorCode = -2000000005
- ParseError (string msg)
- ManyErrorsCode = -2000000006
Sub modules
Result |
Abstract error value
property bool IsExceptional Source #
True if the error is exceptional
property bool IsExpected Source #
True if the error is expected
property bool IsEmpty Source #
This type can contain zero or more errors.
If IsEmpty
is true
then this is like None
in Option
: still an error, but without any specific
information about the error.
This type can contain zero or more errors. This property returns the number of information carrying errors.
If Count
is 0
then this is like None
in Option
: still an error, but without any specific information
about the error.
method bool Is <E> () Source #
If this error represents an exceptional error, then this will return true if the exceptional error is of type E
Get the first error (this will be Errors.None
if there are zero errors)
Get the errors with the head removed (this may be Errors.None
if there are zero errors in the tail)
method Exception ToException () Source #
If this error represents an exceptional error, then this will return that exception, otherwise it will generate a new ErrorException that contains the code, message, and inner of this Error.
method ErrorException ToErrorException () Source #
Convert to an ErrorException
which is like Error
but derived from the Exception
hierarchy
method Error Append (Error error) Source #
Append an error to this error
Single errors will be converted to ManyErrors
; ManyErrors
will have their collection updated
param | error | Error |
returns |
method IEnumerable<Error> AsEnumerable () Source #
method Error New (Exception thisException) Source #
Create an Exceptional
error
param | thisException | Exception |
method Error New (string message, Exception thisException) Source #
Create a Exceptional
error with an overriden message. This can be useful for sanitising the display message
when internally we're carrying the exception.
param | message | Error message |
param | thisException | Exception |
method Error New (int code, string message) Source #
Create an Expected
error
param | code | Error code |
param | message | Error message |
method Error New (int code, string message, Error inner) Source #
Create an Expected
error
param | code | Error code |
param | message | Error message |
param | inner | The inner error to this error |
method Error New (string message, Error inner) Source #
Create an Expected
error
param | message | Error message |
param | inner | The inner error to this error |
method Error Many (params Error[] errors) Source #
Create a ManyErrors
error
Collects many errors into a single Error
type, called ManyErrors
param | code | Error code |
param | inner | The inner error to this error |
method Error Many (Seq<Error> errors) Source #
Create a new error
param | code | Error code |
param | inner | The inner error to this error |
method Error FromObject (object value) Source #
Attempt to recover an error from an object.
Will accept Error, ErrorException, Exception, string, Option
record Expected (string Message, int Code, Option<Error> Inner = default) Source #
Contains the following:
Code
- an integer valueMessage
- display textOption<Error>
- a nested inner error
It returns false
when IsExceptional
is called against it; and true
when IsExpected
is
called against it.
Equality is done via the Code
, so any two Expected
errors with the same Code
will be considered
the same. This is useful when using the @catch
behaviours with the Aff
and Eff
monads. If the
Code
is 0
then equality is done by comparing Message
.
This allows for localised error messages where the message is ignored when matching/catching
param | Message | Error message |
param | Code | Error code |
param | Inner | Optional inner error |
property bool IsExceptional Source #
True if the error is exceptional
property bool IsExpected Source #
True if the error is expected
record Exceptional (string Message, int Code) Source #
This contains an Exception
is the classic sense. This also returns true
when IsExceptional
is
called against it; and false
when IsExpected
is called against it.
If this record is constructed via deserialisation, or the default constructor then the internal Exception
will
will be null
. This is intentional to stop exceptions leaking over application boundaries. The type will
gracefully handle that, but all stack-trace information (and the like) will be erased. It is still considered
an exceptional error however.
property Option<Error> Inner Source #
Returns the inner exception as an Error
(if one exists), None
otherwise
property bool IsExceptional Source #
True if the error is exceptional
property bool IsExpected Source #
True if the error is expected
method Exception ToException () Source #
Gets the Exception
returns |
method ErrorException ToErrorException () Source #
Gets the ErrorException
returns |
record BottomError () Source #
Bottom error
field Error Default = new BottomError() Source #
property bool IsExceptional Source #
True if the error is exceptional
property bool IsExpected Source #
True if the error is expected
method Exception ToException () Source #
Gets the Exception
returns |
method ErrorException ToErrorException () Source #
Gets the ErrorException
returns |
record ManyErrors ([property: DataMember] Seq<Error> Errors) Source #
ManyErrors
allows for zero or more errors to be collected. This is useful for applicative behaviours
like validation. It effectively turns the Error
type into a monoid, with 'zero' being Errors.None
,
and 'append' coming from the Append
method or use of operator+
param | Errors | Errors |
property bool IsExceptional Source #
True if any of the the errors are exceptional
property bool IsExpected Source #
True if all of the the errors are expected
method Exception ToException () Source #
Gets the Exception
method ErrorException ToErrorException () Source #
Gets the ErrorException
Get the first error (this may be Errors.None
if there are zero errors)
Get the errors with the head removed (this may be Errors.None
if there are zero errors in the tail)
method IEnumerable<Error> AsEnumerable () Source #
class ErrorException Source #
Error value
Unlike exceptions, Error
can be either:
Exceptional
- representing an unexpected errorLabelledExceptional
- representing an unexpected error with additional context (a message)Expected
- representing an expected errorManyErrors
- representing an many errors
i.e. it is either created from an exception or it isn't. This allows for expected errors to be represented without throwing exceptions.
property bool IsEmpty Source #
This type can contain zero or more errors. If IsEmpty
is true
then this is like None
in Option
: still
an error, but without any specific information about the error.
property bool IsExceptional Source #
True if the error is exceptional
property bool IsExpected Source #
True if the error is expected
method ErrorException Append (ErrorException error) Source #
Append an error to this error
Single errors will be converted to ManyErrors
; ManyErrors
will have their collection updated
method IEnumerator<ErrorException> GetEnumerator () Source #
method ErrorException New (Exception thisException) Source #
Create a new error
param | message | Error message |
method ErrorException New (string message, Exception thisException) Source #
Create a new error
param | message | Error message |
param | thisException | The exception this error represents |
method ErrorException New (int code, string message) Source #
Create a new error
param | code | Error code |
param | message | Error message |
method ErrorException New (int code, string message, ErrorException inner) Source #
Create a new error
param | code | Error code |
param | message | Error message |
param | inner | The inner error to this error |
method ErrorException New (string message, ErrorException inner) Source #
Create a new error
param | code | Error code |
param | inner | The inner error to this error |
class ExpectedException Source #
Represents expected errors
property bool IsExceptional Source #
True if the error is exceptional
property bool IsExpected Source #
True if the error is expected
constructor ExpectedException (string message, int code, Option<ErrorException> inner) Source #
class ExceptionalException Source #
Represents an exceptional (unexpected) error
param | Exception | Exceptional error |
property Option<ErrorException> Inner Source #
Returns the inner exception as an Error
(if one exists), None otherwise
property bool IsExceptional Source #
True if the error is exceptional
property bool IsExpected Source #
True if the error is expected
constructor ExceptionalException (Exception Exception) Source #
constructor ExceptionalException (string Message, int Code) Source #
constructor ExceptionalException (string Message, Exception Exception) Source #
class ManyExceptions Source #
Represents multiple errors
param | Errors | Errors |
property Option<ErrorException> Inner Source #
Returns the inner exception as an Error
(if one exists), None otherwise
property bool IsEmpty Source #
This type can contain zero or more errors. If IsEmpty
is true
then this is like None
in Option
: still
an error, but without any specific information about the error.
property bool IsExceptional Source #
True if any of the the errors are exceptional
property bool IsExpected Source #
True if all of the the errors are expected
constructor ManyExceptions (Seq<ErrorException> errors) Source #
field Error None = new ManyErrors(Seq<Error>.Empty) Source #
An error state without any error values
field string BottomText = "In a bottom state and therefore cannot proceed. This can happen when an expression couldn't " + "evaluate to a value. This might be due to filter/where, or sometimes if a `struct` wasn't initialised " + "properly (i.e. via `default(T)` or an uninitialised member)." Source #
Bottom error text
field int BottomCode = -2000000001 Source #
Bottom error code
field Error Bottom = BottomError.Default Source #
An error that indicates a value from an operation couldn't be evaluated. This is a hard fail for systems that depend on expressions to produce results.
field string CancelledText = "cancelled" Source #
Cancelled error text
field int CancelledCode = -2000000000 Source #
Cancelled error code
field Error Cancelled = (CancelledCode, CancelledText) Source #
Cancelled error
field string TimedOutText = "timed out" Source #
Timed-out error text
field int TimedOutCode = -2000000002 Source #
Timed-out error code
field Error TimedOut = (TimedOutCode, TimedOutText) Source #
Timed-out error
field string SequenceEmptyText = "sequence empty" Source #
Sequence-empty error text
field int SequenceEmptyCode = -2000000003 Source #
Sequence-empty error code
field Error SequenceEmpty = (SequenceEmptyCode, SequenceEmptyText) Source #
Sequence-empty error
field string ClosedText = "closed" Source #
Closed error text
field int ClosedCode = -2000000004 Source #
Closed error code
field Error Closed = (ClosedCode, ClosedText) Source #
Closed error
field int ParseErrorCode = -2000000005 Source #
Parse error code
field int ManyErrorsCode = -2000000006 Source #
Many errors code
method Error ParseError (string msg) Source #
Parse error