Unlock the Power of Scala's Chaining Utils: A Guide to Tap and Pipe

There is an amazing util in Scala that is available in scala.util.chaining._. It adds two implicit methods to any scala object that allow chain commands (pipe) and apply side effects (tap).

Tap example

import scala.util.chaining._

trait StatsCounter {
    def incr(counterName: String): Unit
}

object Solution extends App {
      val value = 123
      val counter: StatsCounter = ... // implementation
      stringValue(value)
      def stringValue(v: Int): String = {
           // tap adds pure side effect without changing input value
           v.toString.tap { 
                 result => counter.incr(result)
            }
            // this code does the same without chaining
            // val result = v.toString
            // counter.incr(result)
            // result
       }
}

Pipe example

def calculate(value: Int) = {
      value
     .pipe(_ + 100)
     .pipe(Some(_)) 
}

calculate(100) // returns Some(200)

Pipe + Tap example

def calculate(value: Int) = {
     value
     .tap(println)
     .pipe(_ + 100)
     .tap(println)
     .pipe(Some(_))
     .tap(println)
}

calculate(100) 
/* 
returns Some(200)
prints:
100
200
Some(200)
*/

Scala's chaining utils provide a powerful and efficient way to streamline code by enabling the use of tap and pipe methods. By leveraging these methods, developers can optimize their functional code, enhance readability, and improve overall productivity.