Top Related Projects
Asynchronous, Reactive Programming for Scala and Scala.js.
ZIO — A type-safe, composable library for async and concurrent programming in Scala
Build highly concurrent, distributed, and resilient message-driven applications on the JVM
Non-Blocking Reactive Foundation for the JVM
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
An asynchronous programming facility for Scala
Quick Overview
Cats Effect is a high-performance, functional effect system for Scala and Scala.js. It provides a set of abstractions and utilities for working with asynchronous and concurrent computations, allowing developers to write composable, type-safe, and resource-safe code.
Pros
- Functional Approach: Cats Effect promotes a functional programming style, which can lead to more maintainable and testable code.
- Concurrency Primitives: It provides a rich set of concurrency primitives, such as
IO
,Fiber
, andResource
, which simplify the management of asynchronous and concurrent tasks. - Composability: The library's abstractions are highly composable, allowing developers to build complex workflows by combining smaller, reusable components.
- Ecosystem Integration: Cats Effect integrates well with other popular Scala libraries, such as Cats, Monix, and ZIO, making it a versatile choice for building modern Scala applications.
Cons
- Steep Learning Curve: The functional programming concepts and abstractions used in Cats Effect can be challenging for developers new to the paradigm.
- Performance Overhead: The level of abstraction and safety provided by Cats Effect may introduce some performance overhead compared to lower-level concurrency primitives.
- Ecosystem Fragmentation: The Scala ecosystem has several effect systems, which can lead to fragmentation and make it difficult to choose the right tool for a given project.
- Limited Adoption: While Cats Effect is widely used in the Scala community, it may not have the same level of adoption and support as some other Scala libraries.
Code Examples
Here are a few code examples demonstrating the usage of Cats Effect:
Creating and running an IO
computation:
import cats.effect.IO
val computation: IO[Int] = IO.pure(42)
val result: Int = computation.unsafeRunSync()
This code creates an IO
computation that represents the value 42
, and then runs the computation to obtain the result.
Composing IO
computations:
import cats.effect.IO
val computation1: IO[Int] = IO.pure(1)
val computation2: IO[Int] = IO.pure(2)
val result: IO[Int] = for {
a <- computation1
b <- computation2
} yield a + b
This code demonstrates how to compose two IO
computations using for-comprehension, resulting in a new IO
computation that adds the two values.
Using Resource
to manage resources:
import cats.effect.{IO, Resource}
def openFile(path: String): IO[File] = IO.delay(new File(path))
def closeFile(file: File): IO[Unit] = IO.delay(file.close())
val fileResource: Resource[IO, File] = Resource.make(openFile("example.txt"))(closeFile)
val result: IO[Int] = fileResource.use { file =>
// Use the file resource
IO.pure(42)
}
This code shows how to use the Resource
abstraction to safely acquire and release a file resource, ensuring that the file is properly closed even in the presence of exceptions.
Getting Started
To get started with Cats Effect, you can add the following dependency to your build.sbt
file:
libraryDependencies += "org.typelevel" %% "cats-effect" % "3.4.8"
Then, you can start using the IO
monad and other Cats Effect abstractions in your Scala code:
import cats.effect.IO
val computation: IO[Int] = IO.pure(42)
val result: Int = computation.unsafeRunSync()
This code creates a simple IO
computation and runs it to obtain the result. For more advanced usage and examples, please refer to the Cats Effect documentation.
Competitor Comparisons
Asynchronous, Reactive Programming for Scala and Scala.js.
Pros of Monix
- More comprehensive library with additional features like reactive streams and schedulers
- Generally faster performance in benchmarks
- Easier integration with Akka and Play frameworks
Cons of Monix
- Steeper learning curve due to more complex API
- Less frequent updates and potentially slower bug fixes
- Smaller community and ecosystem compared to Cats Effect
Code Comparison
Monix:
import monix.eval.Task
val task = Task.now(42)
val result = task.runSyncUnsafe()
Cats Effect:
import cats.effect.IO
val io = IO.pure(42)
val result = io.unsafeRunSync()
Both libraries provide similar functionality for handling effects, but Monix offers a more extensive set of tools and abstractions. Cats Effect, being part of the Typelevel ecosystem, has better integration with other Cats libraries and a larger community. Monix excels in performance-critical scenarios and offers more advanced features, while Cats Effect focuses on simplicity and ease of use within the Cats ecosystem.
The choice between the two often depends on specific project requirements, existing ecosystem integration, and developer preferences. Both libraries are well-maintained and widely used in the Scala community.
ZIO — A type-safe, composable library for async and concurrent programming in Scala
Pros of ZIO
- Simpler learning curve and more beginner-friendly
- Built-in dependency injection system
- Comprehensive ecosystem with integrated solutions for common tasks
Cons of ZIO
- Less flexible type classes compared to Cats Effect
- Smaller community and fewer third-party libraries
- Opinionated approach may not suit all project styles
Code Comparison
ZIO example:
import zio._
object MyApp extends ZIOAppDefault {
def run = for {
_ <- Console.printLine("Hello, World!")
name <- Console.readLine("What's your name?")
_ <- Console.printLine(s"Hello, $name!")
} yield ()
}
Cats Effect example:
import cats.effect._
import cats.implicits._
object MyApp extends IOApp {
def run(args: List[String]): IO[ExitCode] = for {
_ <- IO.println("Hello, World!")
name <- IO.readLine("What's your name?")
_ <- IO.println(s"Hello, $name!")
} yield ExitCode.Success
}
Both ZIO and Cats Effect are powerful libraries for functional effect management in Scala. ZIO offers a more integrated ecosystem and simpler learning curve, while Cats Effect provides greater flexibility and a larger community. The choice between them often depends on project requirements and team preferences.
Build highly concurrent, distributed, and resilient message-driven applications on the JVM
Pros of Akka
- Mature ecosystem with a wide range of tools and extensions
- Built-in clustering and distributed computing capabilities
- Strong support for reactive programming and event-driven architectures
Cons of Akka
- Steeper learning curve due to its actor-based model
- Potential for increased complexity in smaller applications
- Less emphasis on pure functional programming concepts
Code Comparison
Akka (Actor-based concurrency):
class MyActor extends Actor {
def receive = {
case "hello" => println("Hello, world!")
case _ => println("Unknown message")
}
}
Cats Effect (Functional concurrency):
import cats.effect.IO
val program: IO[Unit] = for {
_ <- IO.println("Hello, world!")
} yield ()
Key Differences
- Akka uses an actor-based model for concurrency, while Cats Effect focuses on functional programming and effect management
- Akka provides built-in tools for distributed systems, whereas Cats Effect is more focused on local concurrency and composability
- Cats Effect emphasizes type safety and referential transparency, while Akka's approach is more flexible but potentially less type-safe
Use Cases
- Akka: Large-scale distributed systems, reactive applications, event-driven architectures
- Cats Effect: Functional programming enthusiasts, applications requiring high composability and type safety, smaller to medium-sized projects
Non-Blocking Reactive Foundation for the JVM
Pros of Reactor Core
- Simpler learning curve for developers familiar with Java's imperative style
- Better integration with Spring ecosystem and other Java frameworks
- More mature and widely adopted in enterprise environments
Cons of Reactor Core
- Less expressive type system compared to Cats Effect's advanced functional programming concepts
- Limited support for pure functional programming patterns
- Potentially more verbose code for complex asynchronous operations
Code Comparison
Reactor Core:
Flux.fromIterable(items)
.flatMap(item -> processItem(item))
.subscribe(result -> System.out.println(result));
Cats Effect:
items.traverse(processItem)
.flatMap(IO.println)
.unsafeRunSync()
Key Differences
- Reactor Core is designed for Java, while Cats Effect is for Scala
- Cats Effect emphasizes pure functional programming and referential transparency
- Reactor Core focuses on reactive programming patterns and backpressure handling
- Cats Effect provides more advanced abstractions for concurrent and parallel computations
- Reactor Core has better tooling support and documentation for enterprise development
Both libraries aim to simplify asynchronous and concurrent programming, but they cater to different programming paradigms and language ecosystems. The choice between them often depends on the project's requirements, team expertise, and existing technology stack.
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
Pros of RxJava
- Mature ecosystem with extensive documentation and community support
- Rich set of operators for complex stream transformations
- Cross-platform compatibility (Android, Java, Kotlin)
Cons of RxJava
- Steeper learning curve due to numerous concepts and operators
- Potential for memory leaks if not managed properly
- Less emphasis on functional programming principles
Code Comparison
RxJava:
Observable.just(1, 2, 3)
.map(i -> i * 2)
.subscribe(System.out::println);
cats-effect:
import cats.effect.IO
val program = for {
_ <- IO.println("Hello")
_ <- IO.println("World")
} yield ()
program.unsafeRunSync()
Key Differences
- RxJava focuses on reactive programming with observables and streams
- cats-effect emphasizes pure functional programming and effect management
- RxJava has a more imperative feel, while cats-effect leans towards declarative programming
Use Cases
- RxJava: Event-driven applications, UI programming, handling asynchronous data streams
- cats-effect: Building robust, concurrent applications with strong type safety and referential transparency
Community and Ecosystem
- RxJava: Large community, widely adopted in Android development
- cats-effect: Growing community, part of the larger Typelevel ecosystem for functional programming in Scala
An asynchronous programming facility for Scala
Pros of Scala Async
- Scala Async provides a more concise and readable syntax for asynchronous programming compared to using raw Futures.
- Scala Async is part of the Scala standard library, making it widely available and well-integrated with the Scala ecosystem.
- Scala Async can be used with both Scala and Java, providing a consistent asynchronous programming model across the JVM.
Cons of Scala Async
- Scala Async is not as flexible or extensible as Cats Effect, which provides a more comprehensive set of abstractions for asynchronous and concurrent programming.
- Scala Async is not actively maintained and developed, unlike Cats Effect which has a large and active community.
- Scala Async may not provide the same level of performance and scalability as Cats Effect, especially for more complex asynchronous use cases.
Code Comparison
Scala Async:
import scala.async.Async.{async, await}
def fetchData(): Future[String] = async {
val data = await(fetchFromDatabase())
data.toUpperCase()
}
Cats Effect:
import cats.effect.IO
def fetchData(): IO[String] = for {
data <- fetchFromDatabase()
} yield data.toUpperCase()
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Cats Effect
Cats Effect is a high-performance, asynchronous, composable framework for building real-world applications in a purely functional style within the Typelevel ecosystem. It provides a concrete tool, known as "the IO
monad", for capturing and controlling actions, often referred to as "effects", that your program wishes to perform within a resource-safe, typed context with seamless support for concurrency and coordination. These effects may be asynchronous (callback-driven) or synchronous (directly returning values); they may return within microseconds or run infinitely.
Even more importantly, Cats Effect defines a set of typeclasses which define what it means to be a purely functional runtime system. These abstractions power a thriving ecosystem consisting of streaming frameworks, JDBC database layers, HTTP servers and clients, asynchronous clients for systems like Redis and MongoDB, and so much more! Additionally, you can leverage these abstractions within your own application to unlock powerful capabilities with little-or-no code changes, for example solving problems such as dependency injection, multiple error channels, shared state across modules, tracing, and more.
Getting Started
- Wired: 3.5.4
- Tired: 2.5.5 (end of life)
libraryDependencies += "org.typelevel" %% "cats-effect" % "3.5.4"
The above represents the core, stable dependency which brings in the entirety of Cats Effect. This is most likely what you want. All current Cats Effect releases are published for Scala 2.12, 2.13, 3.2, and Scala.js 1.13.
Or, if you prefer a less bare-bones starting point, you can try the Giter8 template:
$ sbt new typelevel/ce3.g8
Depending on your use-case, you may want to consider one of the several other modules which are made available within the Cats Effect release. If you're a datatype implementer (like Monix), you probably only want to depend on kernel (the typeclasses) in your compile scope and laws in your test scope:
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-effect-kernel" % "3.5.4",
"org.typelevel" %% "cats-effect-laws" % "3.5.4" % Test)
If you're a middleware framework (like Fs2), you probably want to depend on std, which gives you access to Queue
, Semaphore
, and much more without introducing a hard-dependency on IO
outside of your tests:
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-effect-std" % "3.5.4",
"org.typelevel" %% "cats-effect" % "3.5.4" % Test)
You may also find some utility in the testkit and kernel-testkit projects, which contain TestContext
, generators for IO
, and a few other things:
libraryDependencies += "org.typelevel" %% "cats-effect-testkit" % "3.5.4" % Test
Cats Effect provides backward binary compatibility within the 2.x and 3.x version lines, and both forward and backward compatibility within any major/minor line. This is analogous to the versioning scheme used by Cats itself, as well as other major projects such as Scala.js. Thus, any project depending upon Cats Effect 2.2.1 can be used with libraries compiled against Cats Effect 2.0.0 or 2.2.3, but not with libraries compiled against 2.3.0 or higher.
Updating from Cats Effect 1.x / 2.x
Check out the migration guide!
Hello, World
import cats.effect._
object Main extends IOApp.Simple {
val run = IO.println("Hello, World!")
}
Or, if you need the ability to take arguments and return exit codes:
import cats.effect._
object Main extends IOApp {
def run(args: List[String]): IO[ExitCode] =
if (args.headOption.map(_ == "--do-it").getOrElse(false))
IO.println("I did it!").as(ExitCode.Success)
else
IO.println("Didn't do it").as(ExitCode(-1))
}
Five Simple Rules
Any program written using Cats Effect provides incredibly strong guarantees and powerful functionality, performance, safety, and composability, provided you follow each of the following rules:
- Wrap all side-effects in
delay
,async
,blocking
, orinterruptible
/interruptibleMany
- (pro tip: try to keep the size of your
delay
blocks small; twodelay
s with aflatMap
is much better than one bigdelay
)
- (pro tip: try to keep the size of your
- Use
bracket
orResource
for anything which must beclose
d - Never hard-block a thread outside of
blocking
orinterruptible
/interruptibleMany
- Use
IOApp
instead of writing your owndef main
- Never call anything that has the word
unsafe
in the name
If you follow these rules, and you use libraries and frameworks which also follow these rules, you will get a truly astonishing array of things essentially for free:
- Extremely high performance, elastic, and scalable applications
- Proven backpressure mechanisms under extreme load in real deployments
- Reliable resource safety in all cases
- Aggressive interruption of unnecessary work (e.g. timeouts), automatically, without any extra implementation effort
- Composable and modular application architecture (real, practical functional programming)
- Simple, safe, and incredibly powerful concurrency mechanisms that get faster under high contention
- Highly tuned application runtime with optimized threading and memory management semantics
- Powerful and orthogonal abstractions which enable architectural decomposition that scales to any problem space
- Access to an entire ecosystem of uniquely powerful libraries and tooling
- â¦and so much more
Performance
Most functional and async frameworks will tout their performance on synthetic microbenchmarks, measuring things like how many flatMap
s they can evaluate per microsecond and so on. However, most programs aren't just a bunch of flatMap
s, and the true performance bottlenecks are usually in things like contention scaling under high load, memory and other resource management, backpressure, page faults, and such. In these areas, Cats Effect is truly unrivaled on the JVM, and in most cases, applications written in a purely functional style using Cats Effect will exceed the performance and elasticity of the same applications written in an imperative style.
The chart to the right shows the results of a synthetic benchmark simulating an extremely high-contention scheduling scenario. The scenario is typical of something like a microservice handling extremely high requests-per-second, with each request representing some sort of scatter/gather semantic in which many complex asynchronous actions must be taken in parallel to produce a timely response.
The benchmark measures the performance of a typical "disruptor pattern" application written using a fixed thread pool (from java.util.concurrent.Executors
) compared to the same workflow implemented using Cats Effect (specifically version 3.0). The scores are not a typo: Cats Effect is almost 55x faster than the typical disruptor-style, hand-tuned implementation. Similarly dramatic results are consistently observed when comparing Cats Effect with other popular asynchronous and functional frameworks.
As always, benchmarks are one thing, and your application is its own special snowflake with its own performance profile. Always measure and test your application before assuming that someone else's performance results apply in your use-case. When in doubt, come talk with us and we'll give you an honest opinion!
Abstraction
Cats Effect isn't just designed to enable high performance applications with out-of-the-box safety and elasticity under load. It was intended first and foremost as a tool for implementing composable and reasonable software that is easy to write, easy to test, and easy to evolve as your team and requirements change over time. To achieve this goal, Cats Effect embraces and enables strong, typeful, purely-functional programming styles that are uniquely tailored for the Scala language.
The typical Cats Effect system is often built in terms of simple, orthogonal, primitive capabilities which come together to represent all the expressive power necessary to encode a modern asynchronous runtime. Much like how the rules of addition, multiplication, and integers come together to define much of what we understand about basic arithmetic, so too do the rules of Functor
, Monad
, and Concurrent
come together to define the nature of a program which has all the capabilities you need.
By learning and leveraging these capabilities directly, it is possible to write functions and classes which clearly state their requirements and capabilities in a statically typed and discoverable fashion, improving documentation, readability, and separation of concerns.
And, just as with arithmetic, even when you don't directly leverage the nature of abstract mathematics in your daily life, those laws are still present shaping the world around you and enabling powerful and surprising things like computers and trains and restaurant menus. The laws and abstractions of Cats Effect support a powerful and unique ecosystem of frameworks, giving you access to rich and advanced functionality unparalleled in any language or ecosystem, battle tested in production environments ranging from some of the largest companies in the world to some of the nimblest startups.
Contributing
Please see CONTRIBUTING.md for more details. Lots to do!
Website
To build the documentation site locally, the following dependencies are needed, in addition to sbt
.
- Node (14.x ideally)
- Yarn (any version should work)
NOTE: Nix users can just run nix-shell
at the root directory and follow along the next instructions.
Next, check out the documentation branch along with its submodules.
git checkout --track origin/docs
git submodule update --init --recursive
Finally, build the site.
./build.sh host
If everything goes well, your browser will open at the end of this.
Tool Sponsorship
Development of Cats Effect is generously supported in part by YourKit through the use of their excellent Java profiler.
License
Copyright 2017-2024 Typelevel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Top Related Projects
Asynchronous, Reactive Programming for Scala and Scala.js.
ZIO — A type-safe, composable library for async and concurrent programming in Scala
Build highly concurrent, distributed, and resilient message-driven applications on the JVM
Non-Blocking Reactive Foundation for the JVM
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
An asynchronous programming facility for Scala
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot