typelevel / typelevel/cats-mtl

Rebranding Cats MTL to emphasize the Capabilities, not the Monad Transformers

Open
#516 13 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Scala
Stars
307
Forks
66
Avg merge
6h 23m
Merged PRs (30d)
2

Description

An issue I raised recently with Cats Effect, around WriterT logging not working well with the concurrent parEvalMap in FS2, revealed that the thinking on Cats MTL is shifting.

Cats MTL consists of 2 things:

  • Capability traits like Raise, Tell, Handle and Stateful. These are attached to an abstract effect type F[_] to give it an additional capability. For the 4 traits listed, these capabilities are raising errors, emitting logs, handling errors, and read/writing state, respectively.
  • Implementations of these capability traits, in terms of monad transformer (MT) "stacks" that include an MT suited to the capability; WriterT for emitting logs with Tell, for example.

The documentation currently emphasizes these implementations as the primary role of the library. The homepage leads with the somewhat underwhelming:

Provides transformer typeclasses for cats' Monads, Applicatives and Functors.

You can have multiple cats-mtl transformer typeclasses in scope at once without implicit ambiguity, unlike in pre-1.0.0 cats or Scalaz 7.

However, recent thinking sees more value in the capability traits than the implementations, for at least 2 reasons:

  1. It turns out that MTs prove troublesome in larger, industrial-scale programs that use CE3's Concurrent & friends. https://github.com/typelevel/cats-effect/discussions/3765 is one example of a rash of issues reported in the last couple of years where MTs do surprising things in the presence of concurrency, and consensus is that these surprises are not "fixable". Therefore, we see advice being issued against MT usage, at least in more demanding scenarios.

  2. However, many capability traits can be usefully implemented even without MTs, in ways that are better suited to industrial software development, by backing the trait with a mutable cats.effect.Ref for Tell & Stateful, or by "submarine error propagation" in the case of Raise and Handle.

    Pleasingly, abstraction of the capability is maintained, in that the trait can be implemented either by Ref, or by MT, without touching application code written in terms of the capability. This allows eg unit tests to use a simpler MT-based solution, while larger applications use a Ref approach.

    An example implementation of a Ref-backed Tell:

  def refTell[F[_]: Sync, L, M[_]](ref: Ref[F, M[L]])(using a: Applicative[M], mo: Monoid[M[L]]): Tell[F, L] =
    new Tell[F, L]:
      def tell(l: L): F[Unit] = ref.update(mo.combine(_, a.pure(l)))
      def functor = Functor[F]

The shifting thinking around MTs affects the role that Cats MTL plays in the Typelevel ecosystem. The capability traits are the gold. We ought to:

  • Revise the Homepage and Getting Started to emphasize the value of abstract capabilities, and deemphasize MTs as the only way to fulfill such capability. Instead mention MT, Refs and "submarine error propagation" as implementation options.
  • Show example code on non-MT solutions.

Such a rebranding, perhaps accompanied by a blog post at https://typelevel.org/blog/, could see Cats MTL become relevant to a wider range of Typelevel users and lead to a well-deserved increase in library adoption.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with README.md and docs/getting-started.md, then review the linked Cats Effect discussion and the submarine error propagation example in pull request 489 for context. Revise the documentation to center capability traits, describe MTs, Refs, and submarine error propagation as implementation options, and add non-MT examples.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
documentation
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.