# JIT: IO and Algebraic Substitution

The first key about `IO` types — such as `ZIO` — is that they let you continue to “reason about your code” using the concepts of referential transparency (RT) and algebraic substitution (AS).

## Referential transparency is good

To demonstrate this, here’s a new function named `stringLength`:

``def stringLength(s: String): Int = s.length``

Technically the Scala `String` type already has that `length` method, but ignoring that for now, the important part of `stringLength` is that it’s a pure function. Therefore, in this next example, `fooLength` and `stringLength("foo")` will always and forever have the exact same value (the integer `3`):

``val fooLength = stringLength("foo")``

So now anywhere in your code you can use `fooLength`, `stringLength("foo")`, and the value `3`, and they will always and forever have the same value and mean the same thing.

Now contrast that with an impure method like `io.StdIn.readLine()`:

``val input = io.StdIn.readLine()``

Because people can type an infinite number of things at the command line, the return value of `io.StdIn.readLine()` will almost always be different.

This means that `readLine` is NOT referentially transparent, and we cannot use algebraic substitution with it. In the FP world this is bad, because we want to write our code as algebra.

So, what can we do?

This is where the Haskell people invented the `IO` type.

## IO to the rescue

The way you use an `IO` type is similar to `Try`, looking something like these two examples in the most basic case:

``````val input: IO[String] = IO(io.StdIn.readLine())

def printLater(s: String): IO[Unit] = IO {
println(s)
}``````

A key here is that `IO` is like a wrapper, and a lazy wrapper at that: the code that you pass into `IO` isn’t executed now, it will be executed some time later. This is even true in the first case, where I define `input` as a `val` field.

Because `IO` is lazy, we’re still writing code as a blueprint. Right now we describe what we want, and then some time later that code is actually run.

Instead of thinking of `IO` as a wrapper, you can think of it as a box — and a bit of a time machine as well. Right now it doesn’t contain anything, it’s just like a box with a label on it that describes what will be in it some time later. You can imagine a label being on the box that says, “Some time later this box will contain either (a) a `String` or (b) an error.”

TIP: An `IO` is like getting a receipt from Amazon that “your package will be delivered,” and some time later it will either (a) be delivered just fine (the `Either` happy case), or (b) be damaged (`Either`’s unhappy case). (It may also get lost, but that doesn’t fit with my analogy.)

But right now, as mathematician or architect, you just think of it as an `IO`:

``````+------+
|  IO  |
+------+``````

If you’re familiar with a Scala `Future`, it’s similar to a `Future`, with one big difference: a `Future` begins running immediately, but `IO` is lazy, so nothing happens right now.

### Laziness

We say that code like this is lazy, or lazily evaluated. Haskell is famous for being a language where everything is evaluated lazily. You can write all the Haskell code you want, but nothing will happen until you issue the magic incantation that says, “Run the code now.”

Conversely, all of the code I used to write in Java was strict, or strictly evaluated. For example, when you write Java code like this, it runs right now:

``String input = getInput();``

Frankly, I wrote Java code like this for almost fifteen years, and didn’t even know there was another way to write code.

### Laziness helps with RT

What laziness does for us is that it lets us keep thinking of our code as algebra or a blueprint. We know that we’re working with an `IO` of a specific type — such as an `IO[String]` — and then we merrily keep creating our blueprint, because nothing happens now.

For instance, we can also write a `for` expression using our lazy `IO` values, and again, nothing happens yet:

``````val result = for
_     <- printLater(input)
yield
()``````

As I mentioned, Haskell has a magic incantation that lets you say, “Okay, I’m ready, run the blueprint now.” The Cats Effect and ZIO libraries have a similar incantation, and historically that incantation has been a function named something like `runUnsafe`. This means that when you’re ready to run your entire application — or in this example, just this `for` expression — you run it like this:

``runUnsafe(result)``

The actual function names vary, but the word “unsafe” is an FP way of saying, “Hang on everyone, we’re going to execute the blueprint now, including all those unsafe side effects.” Until now everything was all equations and blueprints, and nothing happened, but now it’s action time.

And now, to wrap up this lesson, I want to add two notes.

## Note 1: Future is not like this

First, it’s important to be clear that the Scala `Future` does not work like this. For example, if the earlier `input` value was written like this:

``val input: Future[String] = Future(doSomeSideEffect())``

the `doSomeSideEffect` function will be run immediately. This is how `Future` works, it runs immediately.

From an FP standpoint, this is bad; it’s a design flaw. The flaw is that `Future` combines the blueprint and its action in the same step. As FPers, we need to be able to layout the blueprint without it starting to run while we’re still working. As a mathematician/architect, we need to be able to separate the what from the when, the description from the execution: `Future`’s action should only be triggered some time later, specifically when `runUnsafe` is invoked.

## Note 2: Call by-name parameters

If you’re wondering how `IO` can be lazy, and you’re not familiar with how call by-name parameters work in Scala, please see the Call By-Name lesson in the Appendix. It explains how this works.