softshipper
softshipper

Reputation: 34081

Describe a computation

I have the following code, that I would like to know, why the variable number gets evaluated twice:

import cats.effect.IO

import scala.util.Random

object Main {

  private val number: IO[Int] =
    IO(Random.between(3, 300))

  def main(args: Array[String]): Unit = {


    number
      .flatMap { e =>
        println(e);
        number
      }.flatMap { e =>
      println(e);
      IO.unit
    }.unsafeRunSync()
  }

}

the program prints two different numbers, although the number is an assignment. I know here, I describe a computation not a execution, and at the end of the universe, I run the program.

The question is, why it prints out two different numbers?

Upvotes: 2

Views: 109

Answers (2)

Micha Wiedenmann
Micha Wiedenmann

Reputation: 20843

There is a difference between

private val number: IO[Int] = IO(Random.nextInt())

and

private val number2: Int = Random.nextInt()

number is a value that when evaluated computes a random number. When evaluated multiple times this value of type IO (aka this computation) is run multiple times resulting in multiple different random numbers.

Whereas number2 when evaluated is just a single number.

It is very similar to the distinction between a lambda (val lambda = () => Random.nextInt()) and a value (val value = Random.nextInt()).

Upvotes: 5

Mario Galic
Mario Galic

Reputation: 48420

IO is a bit similar to the following scenario

final case class SuspendedComputation[T](f: () => T) {
  def run: T = f()
}

val v = SuspendedComputation(Random.nextInt)
v.run
v.run

which outputs something like

v: SuspendedComputation[Int] = SuspendedComputation(<function>
res2: Int = -1062309211
res3: Int = 765640585

Note how SuspendedComputation internally stores computation as () => Random.nextInt and then uses run method to actually evaluate computation f.

Similarly, IO.apply accepts an argument by-name : => A and eventually constructs Delay object that stores the un-evaluated computation in a field as () => A and then uses unsafeRunSync to actually evaluate computation.

Upvotes: 2

Related Questions