Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IO/Task section to FAQ #1227

Merged
merged 2 commits into from
Jul 26, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/src/main/tut/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ section: "faq"
* [Why can't the compiler find implicit instances for Future?](#future-instances)
* [How can I turn my List of `<something>` into a `<something>` of a list?](#traverse)
* [Where is `ListT`?](#listt)
* [Where is `IO`/`Task`?](#task)
* [What does `@typeclass` mean?](#simulacrum)
* [What do types like `?` and `λ` mean?](#kind-projector)
* [What does `macro Ops` do? What is `cats.macros.Ops`?](#machinist)
Expand Down Expand Up @@ -78,6 +79,26 @@ def even(i: Int): ErrorsOr[Int] = if (i % 2 == 0) i.validNel else s"$i is odd".i
nl.traverse(even)
```

## <a id="task" href="#task"></a>Where is IO/Task?

In purely functional programming, a monadic `IO` or `Task` type is often used to handle side effects such as file/network IO. There [have](https://github.com/typelevel/cats/pull/894) [been](https://github.com/typelevel/cats/pull/907) [several](https://github.com/typelevel/cats/issues/1224) GitHub issues/PRs about this and many more Gitter/IRL conversations, but they all seem to arrive at the conclusion that there isn't a clear canonical `IO` or `Task` that serves everyones' needs. Some of the questions that come up are:

- Should tasks be interruptible?
- Should there be a single `Task` that subsumes `IO` and adds support for asynchrony and concurrency, or should there be separate `IO` and `Task` types?
- How should concurrency be managed/configured?
- Is [scala.js](https://www.scala-js.org/) supported?
- Should you be able to block a thread waiting for the result of a task? This is really convenient for tests, but it isn't really compatible with a JavaScript runtime and therefore is an issue for [scala.js](https://www.scala-js.org/).

For some use-cases, a very simple `IO` is the best answer, as it avoids a lot of the overhead and complexity of other solutions. However, other use-cases require low-level concurrency control with asynchrony, resource management, and stack-safety. Considering all of the competing concerns, Cats has opted to not implement its own `IO`/`Task` types and instead encourage users to use a separate library that best serves their use-case.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an alternate approach is use Free and specify the things you need to do, then finally interpret those into Xor, Try or Future at the end of the world. I think this is a good approach too because generally the IO winds up being kind of an Any side-effect when most times you have a pretty narrow scope.

We already have some nice Free docs to point to, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnynek good point. I'll add a note about Free and point to the free docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. Let me know what you think.


Here are a couple libraries with `Task` implementations that you may find useful (in no particular order):
- [Monix](https://monix.io/) - Asynchronous Programming for Scala and [Scala.js](https://www.scala-js.org/).
- The `monix-eval` module provides a full-featured [Task](https://monix.io/docs/2x/eval/task.html) that is both cancellable and Scala.js-compatible.
- [fs2](https://github.com/functional-streams-for-scala/fs2) - Compositional, streaming I/O library for Scala
- fs2 provides a [Task](https://github.com/functional-streams-for-scala/fs2/blob/series/0.9/core/src/main/scala/fs2/task.scala) that is a convenient option if you are already using fs2. At the time of this writing, Scala.js support is [in progress](https://github.com/functional-streams-for-scala/fs2/issues/500).

It may be worth keeping in mind that `IO` and `Task` are pretty blunt instruments (they are essentially the `Any` of side effect management), and you may want to narrow the scope of your effects throughout most of your application. The [free monad]({{ site.baseurl }}/tut/freemonad.html) documentation describes a way to abstractly define controlled effects and interpret them into a type such as `IO` or `Task` (or even simply `Try`, `Future`, or [`Id`]({{ site.baseurl }}/tut/id.html)) as late as possible. As more of your code becomes pure through these controlled effects the less it matters which type you end up choosing to represent your side effects.

## <a id="simulacrum" href="#simulacrum"></a>What does `@typeclass` mean?

Cats defines and implements numerous type classes. Unfortunately, encoding these type classes in Scala can incur a large amount of boilerplate. To address this, [Simulacrum](https://github.com/mpilquist/simulacrum) introduces `@typeclass`, a macro annotation which generates a lot of this boilerplate. This elevates type classes to a first class construct and increases the legibility and maintainability of the code. Use of simulacrum also ensures consistency in how the type classes are encoded across a project. Cats uses simulacrum wherever possible to encode type classes, and you can read more about it at the [project page](https://github.com/mpilquist/simulacrum).
Expand Down