Skip to content

Commit

Permalink
Quick Start update - working on #9
Browse files Browse the repository at this point in the history
  • Loading branch information
bartsokol committed Feb 12, 2018
1 parent 626fe4e commit e2d1cc1
Showing 1 changed file with 24 additions and 2 deletions.
26 changes: 24 additions & 2 deletions docs/QuickStart.md
Expand Up @@ -155,6 +155,28 @@ This should give you a brief overview of how to work with `Option<T>` type, but

## Working with `Result<T>`

Similar to `Option<T>`, `Result<T>` type is a struct and has two possible states - `Ok` with a data of type `T` in the `Value` property, and `Error` with a data of type `ErrorDetails` in the `Error` property. This makes it perfect candidate for second common case, where you have a function and it may fail to execute properly. Usualy in such case you can expect an exception to be thrown. The problem with exceptions is that you don't have any explicit way to say that the function may fail and which exceptions it may throw (apart from comments). Handling exceptions is also problematic, as you need to decide when to wrap the code into `try...catch` - having it everywhere requires a lot of code, and it's also impacting performance quite substantialy. So just like `Option<T>` mitigates the problem of null, `Result<T>` deals with exceptions.
Similar to `Option<T>`, [`Result<T>` type](Result.md) is a struct and has two possible states - `Ok` with a data of type `T` in the `Value` property, and `Error` with a data of type `ErrorDetails` in the `Error` property. This makes it perfect candidate for second common case, where you have a function and it may fail to execute properly. Usualy in such case you can expect an exception to be thrown. The problem with exceptions is that you don't have any explicit way to say that the function may fail and which exceptions it may throw (apart from comments). Handling exceptions is also problematic, as you need to decide when to wrap the code into `try...catch` - having it everywhere requires a lot of code, and it's also impacting performance quite substantialy. So just like `Option<T>` mitigates the problem of null, `Result<T>` deals with exceptions.

TODO
There is very similar set of extensions provided for `Result<T>` to the ones for `Option<T>`. The most important ones like `Bind`, `Map` and `Match` are there, as well as many others. There are also async versions of them, provided in `Monacs.Core.Async` namespace, such as `BindAsync` or `MapAsync`. You can then operate on `Task<Result<T>>`, have async `binder` or `mapper` functions and so on. One thing to remember is that once you jump into async code, you will have to keep using async variants to the the end of the function chain - until you await on the chain and get the underlying `Result<T>`. See the example below:

public async Task<Result<Unit>> UpdateCustomerAddress(UpdateCustomerAddressDto newCustomerAddress)
{
var result = await Validate(newCustomerAddress)
// Validate returns Result<UpdateCustomerAddressDto>
.BindAsync(newAddress => GetCustomer(newAddress.Id).MapAsync(customer => (customer, newAddress)))
// GetCustomer returns Task<Result<Customer>>, so we use MapAsync
.MapAsync(UpdateCustomerAddress)
// UpdateCustomerAddress takes tuple of Customer and UpdateCustomerAddressDto and returns Result<Customer>
.BindAsync(PersistCustomer)
// PersistCustomer returns Task<Result<Customer>>
.DoWhenErrorAsync(LogError);

return result.Ignore();
// result is now Result<Customer>, we can ignore the value (if we use CQRS approach) using non-async extension
}

You can find list of available extensions in the [API documentation](TODO).

## `Unit` - type representing no value

To avoid need to duplicate the APIs for the functions that don't need to return anything (defined as `void` in C#) Monacs uses [`Unit` type](Unit.md), known from other languages (like F#) and libraries (like Reactive Extensions). `Unit` Has only one value and it's available as `Unit.Default` property. You can use it as a substitute for any type whenever you need some, but you don't care about the value, e.g. you can return `Task<Unit>` (equivalent of non-generic `Task`) or `Func<T>` instead of `Action`. `Result<Unit>` can be used as a return type for functions with side effects that don't return any value, e.g. saving data to the database. There are some additional extensions provided for `Result<Unit>` in `Monacs.Core.Unit` namespace, like the mentioned above `Ignore` function.

0 comments on commit e2d1cc1

Please sign in to comment.