FsToolkit.Errorhandling 2.0
source link: https://www.jimmybyrd.me/FsToolkit-ErrorHandling2/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
FsToolkit.Errorhandling 2.0
Introduction
I’m happy to announce FsToolkit.ErrorHandling 2.0. I’ll go over some of the major changes that this release has brought. I’ll be covering things library consumers can use such as:
And I’ll be covering for creators of computation expressions:
- Source member (I can’t find a better resource on it than this StackOverflow post.)
This is part of the 2020 F# Advent event. Take a look at that for other great blog posts coming out.
Applicatives
Applicatives were introduced F# 5.0. We initially added support during F# 5.0 for it PR #75 which was released in 1.3.0 but it’s worth covering it here in the 2.0 announcement.
We’ve added support to the result
asyncResult
taskResult
and jobResult
builders, so you can take advantage of it like:
let myThing : Result<int*int*int ,string> = result {
let! red = Ok 42
and! green = Ok 100
and! blue = Ok 0
return red,green,blue
}
Result:
Ok (42,100,0)
The main attraction here is this is a performance benefit. The one downside with this current implementation is that if there are multiple errors you will only get the first error.
let myThing : Result<int*int*int ,string> = result {
let! red = Ok 42
and! green = Error "Can't be negative"
and! blue = Error "'daba dee daba die' isn't a color"
return red,green,blue
}
Result:
Error "Cant be negative"
It would be nice to have a list of all possible errors. This is where the validation
CE steps in. The type is encoded like
type Validation<'a,'err> = Result<'a, 'err list>
So you can see we’re still using a Result
under the hood but now we’re going to have a list
of 'err
for the return type. So if you change the result
to validation
let myThing : Result<int*int*int ,string list> = validation {
let! red = Ok 42
and! green = Error "Can't be negative"
and! blue = Error "'daba dee daba die' isn't a color"
return red,green,blue
}
Result:
Error ["Cant be negative"; "'daba dee daba die' isn't a color"]
As you can see you now have a list of possible errors. For a more in depth look at the validation CE, take a look at another FsAdvent blog Validation with F# 5 and FsToolkit by CompositionalIT.
Currently there is no implementation for asyncValidation
, taskValidation
, or jobValidation
. I haven’t seen the use case for this but I’m open to Pull Requests for them!
If you want to expand your mind even more around applicatives checkout another great FsAdvent post, Applicative Computation Expressions - 3 by Jeremie Chassaing.
Ply was added in PR #97 thanks to Nino Floris. This is the breaking change that makes us go to 2.0 since we’re replacing TaskBuilder.fs with Ply. Ply “is a high performance TPL library for F#” which also brings along a bigger set of Computation Expressions. (copying for brevity)
builder
return type
tfm
namespace
task
Task<’T>
netstandard2.0, netcoreapp2.1
FSharp.Control.Tasks.Builders
vtask
ValueTask<’T>
netcoreapp2.1
FSharp.Control.Tasks.Builders
unitTask
Task
netstandard2.0, netcoreapp2.1
FSharp.Control.Tasks.Builders
unitVtask
ValueTask
netcoreapp2.1
FSharp.Control.Tasks.Builders
uvtask
ValueTask<’T>
netcoreapp2.1
FSharp.Control.Tasks.Builders.Unsafe
uunitTask
Task
netcoreapp2.1
FSharp.Control.Tasks.Builders.Unsafe
uunintVtask
ValueTask
netcoreapp2.1
FSharp.Control.Tasks.Builders.Unsafe
uply
Ply<’T>
netstandard2.0,netcoreapp2.1
FSharp.Control.Tasks.Builders.Unsafe
Under the covers we’re only using the task
builder since it’s the most flexible but in higher performance scenarios you may want to look at the other builders and decide if making your own vtaskResult
implementation makes sense.
On the initial PR for Ply, we were using Context Insentive tasks (e.g. ConfigureAwait(false)
). In Issue #106 it was brought up this can have performance impacts and there’s some compelling evidence as to why not to use ConfigureAwait(false)
. With PR #107 by Swoorup we are now using Context Sensitive Tasks. I’m still unclear as to what effects this may have on code-bases. From my understanding, this may affect Desktop UI application but not for Server applications. Please open any issues if this does impact your applications.
To convert from using TaskBuilder.fs (assuming you don’t have anything else pulling in Taskbuilder.fs) FSharp.Control.Tasks.V2.ContextInsensitive
with FSharp.Control.Tasks
.
Source overload
The last thing I’d like to cover doesn’t affect consumers of this library but is something that authors of Computation Expression libraries may be unfamiliar with.
I was investigating how FSharp.Control.FusionTasks was handling its binding overloads and I came across an overload I was not familiar with, the Source method. I came across this StackOverflow post that explained it.
The main issue I faced with the current implementation of the result
and friends was maintainability. I had to add so many overloads for BindResult
and MergeSources
to get things to work correctly for different types, such as Choice
. What the Source
member does is remove a lot of that repetitive, unmaintainable code. Essentially, Source
lets an author teach a Computation Expression how to convert different types to a type it knows natively.
Conclusion
This was a pretty big release with regards to changes. Please take it for a spin!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK