2

Why putStrLn in flatMap followed by a result statement didn't get effectively write to stdout?

object Mgr extends App {

  def main1(args: Array[String]) = getStrLn.flatMap { s =>
    putStrLn(s)  // Why this did not write to console?
     UIO.succeed(s)
  }

  override def run(args: List[String]): URIO[zio.ZEnv, Int] = main1(Array()).fold(_ => 1,
    { x =>
       println(x)  // only this line wrote to console, why?
      0
    })
}
Michaelzh
  • 441
  • 5
  • 14

1 Answers1

8

Your problem is basically, that you put two effects into single flatMap.

By invoking putStrLn(s) you're not actually printing to console, you're merely creating the description of the action that will print when your program is interpreted and run (when method run is called). And because in your flatmap only last value is returned (in your case UIO.succeed(s)), then only it will be taken into consideration while constructing ZIO program.

You can fix your program by chaining both actions.

You can do it with *> operator:

def main1(args: Array[String]) = getStrLn.flatMap { s =>
    putStrLn(s)  *>  UIO.succeed(s)
}

or you could just put effects into separate flatMaps. But since you want to create side-effect (by printing value), but then pass value further unchanged, you need to use special function tap:

def main1(args: Array[String]) = getStrLn.tap { s =>
    putStrLn(s)
}.flatMap { s =>
    UIO.succeed(s)
}

Your issue is also described (with other pitfalls) in this great article (look at the first point).

Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76