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
- HasException <E> ()
- HasCode (int code)
- IsType <E> ()
- Is (Error error)
- Filter <E> ()
- ForAllM <M, A> (Func<Error, K<M, A>> f)
- FoldM <M, A> (Func<Error, K<M, A>> f)
- IsExceptional
- IsExpected
- Head
- Tail
- IsEmpty
- Count
- ToException ()
- Exception
- ToErrorException ()
- Combine (Error error)
- Empty
- + (Error lhs, Error rhs)
- AsIterable ()
- 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 ()
- Throw <R> ()
- Expected (string Message, int Code, Option<Error> Inner = default)
- Exceptional (string Message, int Code)
- Message
- Code
- ToString ()
- Inner
- ToException ()
- ToErrorException ()
- HasException <E> ()
- Is (Error error)
- IsExceptional
- IsExpected
- BottomError ()
- Default = new BottomError()
- Code
- Message
- ToString ()
- ToException ()
- ToErrorException ()
- HasException <E> ()
- Is (Error error)
- IsExceptional
- IsExpected
- ManyErrors ([property: DataMember] Seq<Error> Errors)
- Empty
- Code
- Message
- ToString ()
- ToException ()
- ToErrorException ()
- HasException <E> ()
- HasCode (int code)
- IsType <E> ()
- Is (Error error)
- Filter <E> ()
- ForAllM <M, A> (Func<Error, K<M, A>> f)
- FoldM <M, A> (Func<Error, K<M, A>> f)
- IsExceptional
- IsExpected
- Head
- Tail
- IsEmpty
- Count
- AsIterable ()
- ErrorException
- Code
- Inner
- ToError ()
- IsEmpty
- IsExceptional
- IsExpected
- Combine (ErrorException error)
- Empty
- + (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
- WrappedErrorExpectedException
- ExceptionalException
- ExceptionalException (Exception Exception)
- ExceptionalException (string Message, int Code)
- ExceptionalException (string Message, Exception Exception)
- Exception
- Code
- Message
- ToString ()
- Inner
- ToError ()
- IsExceptional
- IsExpected
- Combine (ErrorException error)
- WrappedErrorExceptionalException
- ManyExceptions
- Empty
- Errors = errors
- Code
- Message
- Inner
- ToError ()
- ToString ()
- IsEmpty
- IsExceptional
- IsExpected
- Combine (ErrorException error)
- GetEnumerator ()
- BottomException
- ExceptionExtensions
- 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
- LiftIONotSupportedText = "The IO monad is not in the monad-transformer stack or MonadIO.LiftIO has not been implemented in the trait " + "implementation for your monad-type. Therefore it's not possible to leverage `MonadIO` lifting functionality. " + "To resolve this, implement `MonadIO.LiftIO`."
- LiftIONotSupportedCode = -2000000007
- LiftIONotSupported = (LiftIONotSupportedCode, LiftIONotSupportedText)
- UnliftIONotSupportedText = "The IO monad is not in the monad-transformer stack or MonadIO.ToIO has not been implemented in the trait " + "implementation for your monad-type. Therefore it's not possible to leverage `MonadIO` unlifting trait " + "functionality. To resolve this, implement `MonadIO.ToIO` and/or `MonadIO,MapIO`."
- UnliftIONotSupportedCode = -2000000008
- UnliftIONotSupported = (UnliftIONotSupportedCode, UnliftIONotSupportedText)
- EndOfStreamText = "end of stream"
- EndOfStreamCode = -2000000009
- EndOfStream = (EndOfStreamCode, EndOfStreamText)
- ValidationFailedText = "validation failed"
- ValidationFailedCode = -2000000010
- ValidationFailed = (ValidationFailedCode, ValidationFailedText)
- SourceCompletedText = "source completed"
- SourceCompletedCode = -2000000011
- SourceCompleted = (SourceCompletedCode, SourceCompletedText)
- Exceptions
- None = new ManyExceptions([])
- Bottom = new (Errors.BottomText, Errors.BottomCode)
- Cancelled = new (Errors.CancelledText, Errors.CancelledCode)
- TimedOut = new (Errors.TimedOutText, Errors.TimedOutCode)
- SequenceEmpty = new (Errors.SequenceEmptyText, Errors.SequenceEmptyCode)
- Closed = new (Errors.ClosedText, Errors.ClosedCode)
- ParseErrorCode = -2000000005
- ParseError (string msg)
- LiftIONotSupported = new (Errors.LiftIONotSupportedText, Errors.LiftIONotSupportedCode)
- UnliftIONotSupported = new (Errors.UnliftIONotSupportedText, Errors.UnliftIONotSupportedCode)
- EndOfStream = new (Errors.EndOfStreamText, Errors.EndOfStreamCode)
- ValidationFailed = new (Errors.ValidationFailedText, Errors.ValidationFailedCode)
Abstract error value
property bool IsExceptional Source #
True if the error is exceptional
property bool IsExpected Source #
True if the error is expected
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)
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 HasException <E> () Source #
If this error represents an exceptional error, then this will return true if the exceptional error is of type E
method bool HasCode (int code) Source #
Return true if an Error
with Code
equalling code
is contained within
method bool IsType <E> () Source #
Return true if this error contains or is the error
provided
method Error Filter <E> () Source #
Filter the error(s) so that only errors of type E
are left
If no errors match, then returns Errors.None
.
method K<M, A> ForAllM <M, A> (Func<Error, K<M, A>> f) Source #
For each error in this structure, invoke the f
function and
monad bind it with the subsequent value.
If any f
invocation yields a failure, then subsequent error will
not be processed.
monad
The final A
is returned.
param | f | Function |
returns | The final |
method K<M, A> FoldM <M, A> (Func<Error, K<M, A>> f) Source #
For each error in this structure, invoke the f
function and
monoid combine it with the subsequent value.
If any f
invocation yields a failure, then subsequent error
values may be processed. This is dependent on the M
monoid.
The aggregated K<M, A>
is returned.
param | f | Function |
returns | The aggregated |
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 Combine (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 Iterable<Error> AsIterable () 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
method ErrorException ToErrorException () Source #
Generates a new ErrorException
that contains the Code
, Message
, and Inner
of this Error
.
method bool HasException <E> () Source #
Returns false because this type isn't exceptional
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 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 |
method bool HasException <E> () Source #
Return true if the exceptional error is of type E
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 |
method bool HasException <E> () Source #
Return true if the exceptional error is of type E
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 errors are exceptional
property bool IsExpected Source #
True if all the errors are expected
Get the errors with the head removed (this may be Errors.None
if there are zero errors in the tail)
method Exception ToException () Source #
Gets the Exception
method ErrorException ToErrorException () Source #
Gets the ErrorException
method bool HasException <E> () Source #
Return true if an exception of type E is contained within
method bool HasCode (int code) Source #
Return true if an Error
with Code
equalling code
is contained within
method Error Filter <E> () Source #
Filter the error(s) so that only errors of type E
are left
If no errors match, then returns Errors.None
.
method K<M, A> ForAllM <M, A> (Func<Error, K<M, A>> f) Source #
For each error in this structure, invoke the f
function and
monad bind it with the subsequent value.
If any f
invocation yields a failure, then subsequent error will
not be processed.
monad
The final A
is returned.
param | f | Function |
returns | The final |
method K<M, A> FoldM <M, A> (Func<Error, K<M, A>> f) Source #
For each error in this structure, invoke the f
function and
monoid combine it with the subsequent value.
If any f
invocation yields a failure, then subsequent error
values may be processed. This is dependent on the M
monoid.
The aggregated K<M, A>
is returned.
param | f | Function |
returns | The aggregated |
method Iterable<Error> AsIterable () Source #
class ErrorException Source #
Error value
This is a pair to the Error
type, to allow Error
to be converted to-and-from a classic Exception
.
This allows code that can't handle the Error
type to still throw something that keeps the fidelity of the Error
type, and can be converted directly to an Error
in a catch
block.
Unlike exceptions, Error
can be either:
ExceptionalException
- representing an unexpected errorExpectedException
- representing an expected errorManyExceptions
- representing 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 Combine (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
class WrappedErrorExpectedException Source #
Wraps an Error
maintaining its type for subsequent conversion back to an Error
later
param | Error |
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 WrappedErrorExceptionalException Source #
Wraps an Error
maintaining its type for subsequent conversion back to an Error
later
param | Error |
class ManyExceptions Source #
Represents multiple errors
param | Errors | Errors |
field Seq<ErrorException> Errors = errors Source #
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 errors are exceptional
property bool IsExpected Source #
True if all the errors are expected
class ExceptionExtensions 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
field string LiftIONotSupportedText = "The IO monad is not in the monad-transformer stack or MonadIO.LiftIO has not been implemented in the trait " + "implementation for your monad-type. Therefore it's not possible to leverage `MonadIO` lifting functionality. " + "To resolve this, implement `MonadIO.LiftIO`." Source #
IO monad not in transformer stack text
field int LiftIONotSupportedCode = -2000000007 Source #
IO monad not in transformer stack code
field Error LiftIONotSupported = (LiftIONotSupportedCode, LiftIONotSupportedText) Source #
IO monad not in transformer stack error
field string UnliftIONotSupportedText = "The IO monad is not in the monad-transformer stack or MonadIO.ToIO has not been implemented in the trait " + "implementation for your monad-type. Therefore it's not possible to leverage `MonadIO` unlifting trait " + "functionality. To resolve this, implement `MonadIO.ToIO` and/or `MonadIO,MapIO`." Source #
Transformer stack has no unliftIO support text
field int UnliftIONotSupportedCode = -2000000008 Source #
Transformer stack has no unliftIO support code
field Error UnliftIONotSupported = (UnliftIONotSupportedCode, UnliftIONotSupportedText) Source #
Transformer stack has no unliftIO support error
field string EndOfStreamText = "end of stream" Source #
End-of-stream text
field int EndOfStreamCode = -2000000009 Source #
End-of-stream code
field Error EndOfStream = (EndOfStreamCode, EndOfStreamText) Source #
End-of-stream error
field string ValidationFailedText = "validation failed" Source #
Validation failed text
field int ValidationFailedCode = -2000000010 Source #
Validation failed code
field Error ValidationFailed = (ValidationFailedCode, ValidationFailedText) Source #
Validation failed error
field string SourceCompletedText = "source completed" Source #
Source completed text
field int SourceCompletedCode = -2000000011 Source #
Source completed code
field Error SourceCompleted = (SourceCompletedCode, SourceCompletedText) Source #
Source completed error
method Error ParseError (string msg) Source #
Parse error
class Exceptions Source #
field ErrorException None = new ManyExceptions([]) Source #
An error state without any error values
field ExceptionalException Bottom = new (Errors.BottomText, Errors.BottomCode) 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 ExpectedException Cancelled = new (Errors.CancelledText, Errors.CancelledCode) Source #
Cancelled error
field ExpectedException TimedOut = new (Errors.TimedOutText, Errors.TimedOutCode) Source #
Timed-out error
field ExpectedException SequenceEmpty = new (Errors.SequenceEmptyText, Errors.SequenceEmptyCode) Source #
Sequence-empty error
field ExpectedException Closed = new (Errors.ClosedText, Errors.ClosedCode) Source #
Closed error
field int ParseErrorCode = -2000000005 Source #
Parse error code
field ExceptionalException LiftIONotSupported = new (Errors.LiftIONotSupportedText, Errors.LiftIONotSupportedCode) Source #
IO monad not in transformer stack error
field ExceptionalException UnliftIONotSupported = new (Errors.UnliftIONotSupportedText, Errors.UnliftIONotSupportedCode) Source #
Transformer stack has no unliftIO support error
field ExpectedException EndOfStream = new (Errors.EndOfStreamText, Errors.EndOfStreamCode) Source #
End-of-stream error
field ExpectedException ValidationFailed = new (Errors.ValidationFailedText, Errors.ValidationFailedCode) Source #
Validation failed error
method ExpectedException ParseError (string msg) Source #
Parse error