The following post is an excerpt of the first chapter of the companion book to our new course Essential Effects.

We often use the term effect when talking about the behavior of our code, like “What is the effect of that operation?” or, when debugging, “Doing that shouldn’t have an effect, what’s going on?”, where “what’s going on?” is most likely replaced with an expletive. But what is an effect? Can we talk about effects in precise ways, in order to write better programs that we can better understand?

To explore what effects are, and how we can leverage them, we’ll distinguish two aspects of code: computing values and interacting with the environment. At the same time, we’ll talk about how transparent, or not, our code can be in describing these aspects, and what we as programmers can do about it.

## The Substitution Model of Evaluation

Let’s start with the first aspect, computing values. As a programmer, we write some code, say a method, and it computes a value that gets returned to the caller of that method:

``def plusOne(i: Int): Int = // <1>  i + 1val x = plusOne(plusOne(12)) // <2>``

1. `plusOne` is a method that takes an `Int` argument and produces an `Int` value. We often talk about the type signature, or just signature, of a method. `plusOne` has the type signature `Int => Int`, pronounced "`Int` to `Int`" or "`plusOne` is a function from `Int` to `Int`".
2. `x` is a value. It is defined as the result of evaluating the expression `plusOne(plusOne(12))`.

Let’s use substitution to evaluate this code. We start with the expression `plusOne(plusOne(12))` and substituting each (sub-)expression with its definition, recursively repeating until there are no more sub-expressions:

TIP: We’re displaying the substitution process as a “diff” you might see in a code review. The original expression is prefixed with `-`, and the result of substitution is prefixed with `+`.

1. Replace the inner `plusOne(12)` with its definition:

``- val x = plusOne(plusOne(12))+ val x = plusOne(12 + 1))``
2. Replace `12 + 1` with `13`:

``- val x = plusOne(12 + 1))+ val x = plusOne(13))``
3. Replace `plusOne(13)` with its definition:

``- val x = plusOne(13))+ val x = 13 + 1``
4. Replace `13 + 1` with `14`:

``- val x = 13 + 1+ val x = 14``

It is important to notice some particular properties of this example:

1. To understand what `plusOne` does, you don’t have to look anywhere except the (literal) definition of `plusOne`. There are no references to anything outside of it. This is sometimes referred to as local reasoning.
2. Under substitution, programs mean the same thing if they evaluate to the same value. `13 + 1` means exactly the same thing as `14`. So does `plusOne(12 + 1)`, or even `(12 + 1) + 1`.

To quote myself while teaching an introductory course on functional programming, “[substitution] is so stupid, even a computer can do it!”. It would be fantastic if all programs were as self-contained as `plusOne`, so we humans could use substitution, just like the machine, to evaluate code. But not all code is compatible with substitution.

### When does substitution break down?

Take a minute to think of some examples of expressions where substitution doesn’t work. What about them breaks substitution?

Here are a few examples you might have thought of:

1. When printing to the console.

The `println` function prints a string to the console, and has the return type `Unit`. If we apply substitution,

``- val x = println("Hello world!")+ val x = ()``

the meaning–the effect–of the first expression is very different from the second expression. Nothing is printed in the latter. Using substitution doesn’t do what we intend.

2. When reading values from the outside world.

If we apply substitution,

``- val name = readLine+ val name = <whatever you typed in the console>``

`name` evaluates to whatever particular string was read from the console, but that particular string is not the same as the evaluation of the expression `readLine`. The expression `readLine` could evaluate to something else.

3. When expressions refer to mutable variables.

If we interact with mutable variables, the value of an expression depends any possible change to the variable. In the following example, if any code changes the value of `i`, then that would change the evaluation of `x` as well.

``var i = 12- val x = { i += 1; i }+ val x = 13``

(This example is very similar to the previous one.)

## Dealing with Side-effects

The second aspect of effects, after computing values, is interacting with the environment. And as we’ve seen, this can break substitution. Environments can change, they are non-deterministic, so expressions involving them do not necessarily evaluate to the same value. If we use mutable state, if we perform hidden side-effects–if we break substitution–is all lost? Not at all.

One way we can maintain the ability to reason about code is to localize the “impure” code that breaks substitution. To the outside world, the code will look–and evaluate–as if substitution is taking place. But inside the boundary, there be dragons:

``def sum(ints: List[Int]): Int = {  var sum = 0 // <1>  ints.foreach(i => sum += i)  sum}sum(List(1, 2, 3)) // <2>``
1. We’ve used a mutable variable. The horrors! But nothing outside of `sum` can ever affect it. Its existence is localized to a single invocation.
2. When we evaluate the expression that uses `sum`, we get a deterministic answer. Substitution works at this level.

We’ve optimized, in a debatable way, code to compute the sum of a list, so instead of using an immutable fold over the list we’re updating a local variable. From the caller’s point to view, substitution is maintained. Within the impure code, we can’t leverage the reasoning that substitution gives us, so to prove to ourselves the code behaved we’d have to use other techniques that are outside the scope of this book.

Localization is a nice trick, but won’t work for everything that breaks substitution. We need side-effects to actually do something in our programs, but side-effects are unsafe! What can we do?

## The Effect Pattern

If we impose some conditions, we can tame the side-effects into something safer; we’ll call these effects. There are two parts:

1. The type of the program should tell us what kind of effects the program will perform, in addition to the type of the value it will produce.
One problem with impure code is we can’t see that it is impure! From the outside it looks like a method or block of code. By giving the effect a type we can distinguish it from other code. At the same time, we continue to track the type of the result of the computation.
2. If the behavior we want relies upon some externally-visible side-effect, we separate describing the effects we want to happen from actually making them happen. We can freely substitute the description of effects up until the point we run them.
This idea is exactly the same as the localization idea, except that instead of performing the side-effect at the innermost layer of code and hiding it from the outer layers, we delay the the side-effect so it executes outside of any evaluation, ensuring substitution still holds within.

We’ll call these conditions the Effect Pattern, and apply it to studying and describing the effects we use every day, and to new kinds of effects.

### Example: Is `Option` an Effect?

The `Option` type represents the optionality of a value: we have some value, or we have none. In Scala it is encoded as an algebraic data type:

``sealed trait Option[+A]case class Some[A](value: A) extends Option[A]case object None extends Option[Nothing]``

Is `Option[A]` an effect? Let’s check the criteria:

1. Does `Option[A]` tell us what kind of effects the program will perform, in addition to the type of the value it will produce?
Yes: if we have a value of type `Option[A]`, we know the effect is optionality from the name `Option`, and we know it may produce a value of type `A` from the type parameter `A`.
2. Are externally-visible side-effects required?
Not really. The `Option` algebraic data type is an interface representing optionality that maintains substitution. We can replace a method call with its implementation and the meaning of the program won’t change.

There is one exception–pun intended–where an externally-visible side-effect might occur:

``def get(): A =  this match {    case Some(a) => a    case None => throw new NoSuchElementException("None.get")  }``

Calling `get` on a `None` is a programmer error, and raises an exception which in turn may result in a stack trace being printed. However this side-effect is not core to the concept of exceptions, it is just the implementation of the default exception handler. The essence of exceptions is non-local control flow: a jump to an exception handler in the dynamic scope. This is not an externally-visible side effect.

With these two criteria satisfied, we can say yes, `Option[A]` is an effect!

It may seem strange to call `Option` an effect since it doesn’t perform any side-effects. The point of the first condition of the Effect Pattern is that the type should make the presence of an effect visible. A traditional alternative to `Option` would be to use a `null` value, but then how could you tell that a value of type `A` could be `null` or not? Some types which could have a `null` value are not intended to have the concept of a missing value. `Option` makes this distinction apparent.

### Example: Is `Future` an Effect?

`Future` is known to have issues that aren’t easily seen. For example, look at this code, where we reference the same `Future` to run it twice:

``val print = Future(println("Hello World!"))val twice =  print    .flatMap(_ => print)``

What output is produced?

``````Hello World!
``````

It is only printed once! Why is that?

The reason is that the `Future` is scheduled to be run immediately upon construction. So the side-effect will happen (almost) immediately, even when other “descriptive” operations–the subsequent `print` in the `flatMap`—happen later. That is, we describe performing `print` twice, but the side-effect is only executed once!

Compare this to what happens when we substitute the definition of `print` into `twice`:

1. Replace the first reference to `print` with its definition:
``  val print = Future(println("Hello World!"))  val twice =-   print+   Future(println("Hello World!"))      .flatMap(_ => print)``
2. Replace the second reference to `print` with its definition, and remove the definition of `print` since it has been inlined.
``- val print = Future(println("Hello World!"))  val twice =    Future(println("Hello World!"))-     .flatMap(_ => print)+     .flatMap(_ => Future(println("Hello World!")))``

We now have:

``val twice =  Future(println("Hello World!"))    .flatMap(_ => Future(println("Hello World!")))``

Running it, we then see:

``````Hello World!
Hello World!
``````

This is why we say `Future` is not an effect: when we do not separate effect description from execution, as per our Effect Pattern, substitution of expressions with their definitions doesn’t have the same meaning,

## Capturing Arbitrary Side-Effects as an Effect

We’ve seen the `Option` effect type, which doesn’t involve side-effects, and we’ve examined why `Future` isn’t an effect. So what about an effect that does involve side-effects, but safely?

This is the purpose of the `IO` effect type in `cats.effect`. It is a data type that allows us to capture any side-effect, but in a safe way, following our Effect Pattern. We’ll first build our own version of `IO` to understand how it works.

### A simple `MyIO` data type

``case class MyIO[A](unsafeRun: () => A) { // <1>  def map[B](f: A => B): MyIO[B] =    MyIO(() => f(unsafeRun())) // <2>  def flatMap[B](f: A => MyIO[B]): MyIO[B] =    MyIO(() => f(unsafeRun()).unsafeRun()) // <2>}``
1. When we construct an `MyIO` value, we give it a function which computes the result and may perform side-effects, but don’t invoke it yet. When we want to execute the side-effect, we call `unsafeRun`.
2. We can compose our `MyIO` value to produce new `MyIO` values using `map` and `flatMap`. But notice we always create a new `MyIO` value, with its own delayed `unsafeRun` side-effect, to ensure no side-effects are executed until the outer `unsafeRun` is invoked.

For example, we might define printing to the console as an `MyIO` value:

``def putStr(s: => String): MyIO[Unit] =  MyIO(() => println(s))val hello = putStr("hello!")val world = putStr("world!")val helloWorld =  for {    _ <- hello    _ <- world  } yield ()helloWorld.unsafeRun()``

which outputs

``````hello!
world!
``````

### `MyIO` as an Effect

Let’s check `MyIO` against our Effect Pattern:

1. Does the type of the program tell us…
a. What kind of effects the program will perform?
An `MyIO` represents a (possibly) side-effecting computation.
b. What type of value will it will produce?
A value of type `A`, if the computation is successful.
2. When externally-visible side-effects are required, is the effect description separate from the execution?
Externally-visible side-effects are required: the `unsafeRun` method of an `MyIO` can do anything, including side-effects.
We describe `MyIO` values by constructing them and by composing with methods like `map` and `flatMap`. The execution of the effect only happens when the `unsafeRun` method is called.

Therefore, `MyIO` is an effect!

By satisfying the Effect Pattern we know the `MyIO` effect type is safe to use, even when programming with side-effects. At any point before we invoke `unsafeRun` we can rely on substitution, and therefore we can replace any expression with its value–and vice-versa–to safely refactor our code.

The `cats.effect.IO` data type uses very similar techniques to isolate the captured side-effect from any methods used for composition.

## Summary

1. The substitution model of evaluation gives us local reasoning and fearless refactoring.
2. Interacting with the environment can break substitution. We can localize these side-effects so they don’t affect evaluation.
3. The Effect Pattern is a set of conditions that makes the presence of effects more visible while ensuring substitution is maintained. An effect’s type tells us what kind of effects the program will perform, in addition to the type of the value it will produce. Effects separate describing what we want to happen from actually making them happen. We can freely substitute the description of effects up until the point we run them.
4. We created the `MyIO[A]` effect, which delayed the side-effect until the `unsafeRun` method is called. We produced new `MyIO` values with the `map` and `flatMap` combinators. `cats-effect` and other implementations of the `IO` monad allow us to safely program and refactor our programs, even in the presence of side-effects.