1

I'm trying to come up with different examples in order to understand the work of Keep.left or Keep.right

I have the following code:

val numSource = Source(1 to 10)
  val numSource = Source(1 to 10)
  val incrementFlow = Flow[Int].map(x => x +1)
  val doubleFlow = Flow[Int].map(x => x * 10)

  val someFuture: NotUsed =           numSource.via(incrementFlow).via(doubleFlow).to(Sink.foreach(println)).run
  val someOtherFuture: Future[Done] = numSource.viaMat(incrementFlow)(Keep.left).viaMat(doubleFlow)(Keep.right).toMat(Sink.foreach(println))(Keep.right).run()
  val someOtherFuture2: Future[Done] = numSource.viaMat(incrementFlow)(Keep.right).viaMat(doubleFlow)(Keep.right).toMat(Sink.foreach(println))(Keep.right).run()

I was assuming that in someOtherFuture viaMat(incrementFlow)(Keep.left) will ignore the increment of the element since I'm using materialized value of the source (and not the resulted one = Keep.right) and the result of the graph will be equal to num * 10. BUT all 3 lines are giving me back the same result: //20,30,40 .. 110

What I'm missing here? I have already checked the documentation and was trying to implement simple examples, but it looks that I got wrong the idea of materializing. Or maybe it happens since I'm working with a sequenced graph w/o any merged flows that receive two inputs?

Levi Ramsey
  • 18,884
  • 1
  • 16
  • 30
nikabu
  • 127
  • 1
  • 6
  • 1
    Does this answer your question? [How does Akka Stream's Keep right/left/both result in a different output?](https://stackoverflow.com/questions/62682901/how-does-akka-streams-keep-right-left-both-result-in-a-different-output) – Levi Ramsey Jun 29 '21 at 14:08
  • @LeviRamsey I saw this post, that's why I assumed that toMat(Sink..)(Keep.right) will keep the value. Can you please assist me with understanding of how I can skip on results of incrementFlow and just to use its input for the doubleFlow? – nikabu Jun 29 '21 at 15:10
  • The materialized value doesn't in general affect the values flowing through the stream, so since you have the same values from `numSource` with each materialization and the functions in the `map`s are deterministic, you'll always get the same values. – Levi Ramsey Jun 29 '21 at 15:32
  • In your examples, the materialized value is just the result that gets handed back when you actually start running the stream (the `NotUsed` (to signal that there's nothing useful) and the `Future[Done]` (which will complete when the stream finishes or report what error caused the stream to fail) in your example) – Levi Ramsey Jun 29 '21 at 15:34

1 Answers1

1

The materialized value is best understood as a means for code outside of a stream which has started (whether still running or completed/failed) to interact with the stream in some way: it's the return value of running the stream, and we can see the effect of Keep.right/Keep.left in the code you posted:

val someFuture: NotUsed =           numSource.via(incrementFlow).via(doubleFlow).to(Sink.foreach(println)).run
val someOtherFuture: Future[Done] = numSource.viaMat(incrementFlow)(Keep.left).viaMat(doubleFlow)(Keep.right).toMat(Sink.foreach(println))(Keep.right).run()
val someOtherFuture2: Future[Done] = numSource.viaMat(incrementFlow)(Keep.right).viaMat(doubleFlow)(Keep.right).toMat(Sink.foreach(println))(Keep.right).run()

The materialized value of numSource, incrementFlow, and doubleFlow is NotUsed which basically means that those stages don't expose any way for code outside of the stream to interact with the stream.

For Sink.foreach, the materialized value is a Future[Done] which will complete successfully with Done if the stream runs until the source has exhausted and all other stages succeeded, or complete with a failure containing the cause of the stream failing.

Levi Ramsey
  • 18,884
  • 1
  • 16
  • 30
  • many thanks for this excellent explanation. Is there a way to convert source or one of the flows from my example to the valuable type instead of `NotUsed`? In AKKA documentation, source is usually defined as `NotUsed` – nikabu Jun 29 '21 at 18:51
  • Most of the predefined `Source`s/`Flow`s have a `NotUsed` materialized value because there's not really anything that would make sense. There is `mapMaterializedValue`, which lets you convert the materialized value, though there's not really anything you could sanely convert `NotUsed` to. – Levi Ramsey Jun 29 '21 at 19:18