Skip to content

Commit

Permalink
doc: Update
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmah309 committed Nov 18, 2024
1 parent 4d5da3c commit 8bfa0b2
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 32 deletions.
27 changes: 13 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@ an implementation of the popular Rust crate with the same name - [anyhow].
errors do arise, you can add `context` to better understand the situation that led to the errors.
See [here](#the-better-way-to-handle-errors-with-anyhow) to jump right into an example.

## Table of Contents

1. [What Is a Result Monad Type And Why Use it?](#what-is-a-result-monad-type-and-why-use-it)
2. [The Better Way To Handle Errors With Anyhow](#the-better-way-to-handle-errors-with-anyhow)
- [Example](#the-better-way-to-handle-errors-with-anyhow)
- [What Would This Look Like Without Anyhow](#what-would-this-look-like-without-anyhow)
3. [Configuration Options](#configuration-options)
4. [Base Result Type vs Anyhow Result Type](#base-result-type-vs-anyhow-result-type)

## What Is a Result Monad Type And Why Use it?
If you are not familiar with the `Result` type, why it is needed, or it's usages, you can read up on all that here:
[article](https://mcmah309.github.io/#/blog/the_result_type_in_dart)
Expand Down Expand Up @@ -164,7 +155,7 @@ StackTrace:
* `stackTraceDisplayModifier`: Modifies the stacktrace during display. Useful for adjusting
number of frames to include during display/logging.

### Anyhow Result Type vs Rust Result Type
## Anyhow Result Type vs Rust Result Type
The `Result` type for this package is just a typedef of the `Result` type in the [rust] package -
```dart
import 'package:rust/rust.dart' as rust;
Expand Down Expand Up @@ -193,7 +184,7 @@ void main(){
}
```

### Downcasting
## Downcasting
Downcasting is the process of getting the underlying error from an an anyhow `Error`.
```dart
import 'package:anyhow/anyhow.dart';
Expand All @@ -210,11 +201,19 @@ This may be useful when you want to inspect the root error type.
import 'package:anyhow/anyhow.dart';
void main(){
Result<int> x = bail("this is an error message").context("Other context");
Error error = x.unwrapErr().rootCause();
assert(error.downcastUnchecked() == "this is an error message");
Result<int> x = bail("this is an error message").context(1);
final rootInner = x.unwrapErr().rootCause().downcastUnchecked();
switch(rootInner) {
case String():
print("String found");
default:
print("Default reached");
}
}
```
Since anyhow makes the trade off that you do not care about the underlying causes inner type,
which allows your api's to be more composable and concise,
downcasting is expected to be used sparingly. Thus being most useful in applications.

[anyhow]: https://docs.rs/anyhow/latest/anyhow/
[rust]: https://pub.dev/packages/rust_core
15 changes: 12 additions & 3 deletions example/working_with_anyhow_errors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@ void main() {
for (final (index, chainedErr) in err.unwrapErr().chain().indexed) {
print("chain $index: ${chainedErr.downcast<String>().unwrap()}");
}
final root = err.unwrapErr().rootCause();
if (root.isType<String>()) {
String rootErr = root.downcast<String>().unwrap();
var rootError = err.unwrapErr().rootCause();
if (rootError.isType<String>()) {
String rootErr = rootError.downcast<String>().unwrap();
print("The root error was a String with root value '$rootErr'");
}
Result<int> x = bail("this is an error message").context(1).into();
var rootInner = x.unwrapErr().rootCause().downcastUnchecked();
switch(rootInner) {
case String():
print("String found");
default:
print("Default reached");
}
}
// Output:
// Error: This is a single error
Expand All @@ -24,3 +32,4 @@ void main() {
// chain 1: This is context for the error
// chain 2: This is single error
// The root error was a String with root value 'This is a single error'
// String found
28 changes: 14 additions & 14 deletions lib/src/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,35 @@ class Error implements Exception {
/// Requires [hasStackTrace] = true
static StackTrace Function(StackTrace) stackTraceDisplayModifier = (s) => s;

Object _cause;
Object _inner;
Error? _parent;
late final StackTrace? _stackTrace;

Error(this._cause, {Error? parent}) : _parent = parent {
Error(this._inner, {Error? parent}) : _parent = parent {
_stackTrace = hasStackTrace ? StackTrace.current : null;
}

/// Constructor used internally when it is known a [StackTrace] is needed, so it is eagerly created.
Error._withStackTrace(this._cause, this._stackTrace, {Error? parent})
Error._withStackTrace(this._inner, this._stackTrace, {Error? parent})
: _parent = parent;

/// Returns true if [E] is the type held by this error object.
bool isType<E extends Object>() {
return _cause is E;
return _inner is E;
}

/// Attempt to downcast the error object to a concrete type.
Result<E> downcast<E extends Object>() {
if (_cause is E) {
return Ok(_cause as E);
if (_inner is E) {
return Ok(_inner as E);
}
return Err(this);
}

/// Attempt to downcast the error object to a concrete type without error handling. If the downcast fails, this will throw an exception.
/// This is useful when you know the downcast should always succeed, like when casting to [Object] for use in a case statement.
E downcastUnchecked<E extends Object>() {
return _cause as E;
return _inner as E;
}

/// The lowest level cause of this error — this error’s cause’s cause’s cause etc. The root cause is the last error
Expand All @@ -79,8 +79,8 @@ class Error implements Exception {
StackTrace? stacktrace() => _stackTrace;

/// Creates a clone of this [Error], cloning all [Error], but the causes are not cloned.
Error clone<E extends Object>({E? cause, Error? parent}) {
return Error(cause ?? _cause, parent: parent ?? _parent?.clone());
Error clone({Object? inner, Error? parent}) {
return Error(inner ?? _inner, parent: parent ?? _parent?.clone());
}

/// Human readable error representation
Expand All @@ -106,13 +106,13 @@ class Error implements Exception {
void _writeErrorAndContext(StringBuffer stringBuf, String firstTitle,
String restTitle, Iterator<Error> iter) {
iter.moveNext();
stringBuf.write("$firstTitle: ${iter.current._cause}\n");
stringBuf.write("$firstTitle: ${iter.current._inner}\n");
if (iter.moveNext()) {
stringBuf.write("\n$restTitle:\n");
stringBuf.write("\t0: ${iter.current._cause}\n");
stringBuf.write("\t0: ${iter.current._inner}\n");
int index = 1;
while (iter.moveNext()) {
stringBuf.write("\t${index}: ${iter.current._cause}\n");
stringBuf.write("\t${index}: ${iter.current._inner}\n");
index++;
}
}
Expand Down Expand Up @@ -153,11 +153,11 @@ class Error implements Exception {
}

@override
int get hashCode => _cause.hashCode;
int get hashCode => _inner.hashCode;

@override
bool operator ==(Object other) =>
other is Error && other._cause == _cause && other._parent == _parent;
other is Error && other._inner == _inner && other._parent == _parent;
}

/// Controls the base [toString] format
Expand Down
2 changes: 1 addition & 1 deletion lib/src/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ extension AnyhowIterableResultExtensions<S> on Iterable<Result<S>> {
}
}
if (result.isErr()) {
finalResult = finalResult.context(result.unwrapErr()._cause);
finalResult = finalResult.context(result.unwrapErr()._inner);
}
}
return finalResult;
Expand Down

0 comments on commit 8bfa0b2

Please sign in to comment.