---
title: Introduction
layout: gem-single
type: gem
name: dry-effects
sections:
  - effects
---

`dry-effects` is a practical, production-oriented implementation of algebraic effects in Ruby.

### Why?

Algebraic effects are a powerful tool for writing composable and testable code in a safe way. Fundamentally, any effect consists of two parts: introduction (throwing effect) and elimination (handling effect with an _effect provider_). One of the many things you can do with them is sharing state:

```ruby
require 'dry/effects'

class CounterMiddleware
  # This adds a `counter` effect provider. It will handle (eliminate) effects
  include Dry::Effects::Handler.State(:counter)

  def initialize(app)
    @app = app
  end

  def call(env)
    # Calling `with_counter` makes the value available anywhere in `@app.call`
    counter, response = with_counter(0) do
      @app.(env)
    end

    # Once processing is complete, the result value
    # will be stored in `counter`

    response
  end
end

### Somewhere deep in your app

class CreatePost
  # Adds counter accessor (by introducing state effects)
  include Dry::Effects.State(:counter)

  def call(values)
    # Value is passed from middleware
    self.counter += 1
    # ...
  end
end
```

`CreatePost#call` can only be called when there's `with_counter` somewhere in the stack. If you want to test `CreatePost` separately, you'll need to use `with_counter` in tests too:

```ruby
require 'dry/effects'
require 'posting_app/create_post'

RSpec.describe CreatePost do
  include Dry::Effects::Handler::State(:counter)

  subject(:create_post) { described_class.new }

  it 'updates the counter' do
    counter, post = with_counter(0) { create_post.(post_values) }

    expect(counter).to be(1)
  end
end
```

Any introduced effect must have a handler. If no handler found you'll see an error:

```ruby
CreatePost.new.({})
# => Dry::Effects::Errors::MissingStateError (Value of +counter+ is not set, you need to provide value with an effect handler)
```

In a statically typed with support for algebraic effects you won't be able to run code without providing all required handlers, it'd be a type error.

It may remind you using global state, but it's not actually global. It should instead be called "goto on steroids" or "goto made unharmful."

### Cmp

State sharing is one of many effects already supported; another example is comparative execution. Imagine you test a new feature that ideally shouldn't affect application responses.

```ruby
require 'dry/effects'

class TestNewFeatureMiddleware
  # `as:` renames handler method
  include Dry::Effects::Handler.Cmp(:feature, as: :test_feature)

  def initialize(app)
    @app = app
  end

  def call(env)
    without_feature, with_feature = test_feature do
      @app.(env)
    end

    if with_feature != without_feature
      # something is different!
    end

    without_feature
  end
end

### Somewhere deep in your app

class PostView
  include Dry::Effects.Cmp(:feature)

  def call
    if feature?
      # do render with feature
    else
      # do render without feature
    end
  end
end
```

The `Cmp` provider will run your code twice so that you can compare the results and detect differences.

### Composition

So far effects haven't shown anything algebraic about themselves. Here comes composition. Any effect is composable with one another. Say we have code using both `State` and `Cmp` effects:

```ruby
require 'dry/effects'

class GreetUser
  include Dry::Effects.Cmp(:excitement)
  include Dry::Effects.State(:greetings_given)

  def call(name)
    self.greetings_given += 1

    if excitement?
      "#{greetings_given}. Hello #{name}!"
    else
      "#{greetings_given}. Hello #{name}"
    end
  end
end
```

It's a simple piece of code that requires a single argument and two effect handlers to run:

```ruby
class Context
  include Dry::Effects::Handler.Cmp(:excitement, as: :test_excitement)
  include Dry::Effects::Handler.State(:greetings_given)

  def initialize
    @greeting = GreetUser.new
  end

  def call(name)
    test_excitement do
      with_greetings_given(0) do
        @greeting.(name)
      end
    end
  end
end

Context.new.('Alice')
# => [[1, "1. Hello Alice"], [1, "1. Hello Alice!"]]
```

The result is two branches with `excitement=false` and `excitement=true`. Every variant has its state handler and hence returns another array with the number of greetings given and the greeting. However, neither our code nor algebraic effects restrict the order in which the effects are meant to be handled so let's swap the handlers:

```ruby
class Context
  # ...
  def call(name)
    with_greetings_given(0) do
      test_excitement do
        @greeting.(name)
      end
    end
  end
end

Context.new.('Alice')
# => [2, ["1. Hello Alice", "2. Hello Alice!"]]
```

Now the same code returns a different result! Even more, it has a different shape (or type, if you will): `((Integer, String), (Integer, String))` vs. `(Integer, (String, String))`!

### Algebraic effects

Algebraic effects are relatively recent research describing a possible implementation of the effect system. An effect is some capability your code requires to be executed. It gives control over what your code does and helps a lot with testing without involving any magic like `allow(Time).to receive(:now).and_return(@time_now)`. Instead, getting the current time is just another effect, as simple as that.

Algebraic effects lean towards functional programming enabling things like dependency injection, mutable state, obtaining the current time and random values in pure code. All that is done avoiding troubles accompanying monad stacks and monad transformers. Even things like JavaScript's `async`/`await` and Python's `asyncio` can be generalized with algebraic effects.

If you're interested in the subject, there is a list of articles, papers, and videos, in no particular order:

- [Algebraic Effects for the Rest of Us](https://overreacted.io/algebraic-effects-for-the-rest-of-us/) by Dan Abramov, an (unsophisticated) introduction for React/JavaScript developers.
- [An Introduction to Algebraic Effects and Handlers](https://www.eff-lang.org/handlers-tutorial.pdf) is an approachable paper describing the semantics. Take a look if you want to know more on the subject.
- [Algebraic Effects for Functional Programming](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/08/algeff-tr-2016-v2.pdf) is another paper by Microsoft Research.
- [Asynchrony with Algebraic Effects](https://www.youtube.com/watch?v=hrBq8R_kxI0) intro given by Daan Leijen, the author of the previous paper and the [Koka](https://github.com/koka-lang/koka) programming language created specifically for exploring algebraic effects.
- [Do Be Do Be Do](https://arxiv.org/pdf/1611.09259.pdf) describes the Frank programming language with typed effects and ML-like syntax.

### Goal of dry-effects

Despite different effects are compatible one with each other, libraries implementing them (not using them!) are not compatible out of the box. `dry-effects` is aimed to be the standard implementation across dry-rb and rom-rb gems (and possibly others).