I struggle to apply the idea of implicit
in Scala to Akka Streams.
According to http://docs.scala-lang.org/overviews/core/implicit-classes.html, the basic concept of an implicit
class in Scala is that for 5 times prinln("foo")
an object of IntWithTimes
is created, making the method times
implicitly available through importing Helpers._
.
object Helpers {
implicit class IntWithTimes(x: Int) {
def times[A](f: => A): Unit = {
def loop(current: Int): Unit =
if(current > 0) {
f
loop(current - 1)
}
loop(x)
}
}
}
Let's consider the following example:
val g = RunnableGraph.fromGraph(GraphDSL.create() {
implicit builder: GraphDSL.Builder[Unit] =>
import GraphDSL.Implicits._
val in = Source(1 to 100)
val flow = Flow[Int].map(_ + 1)
val out = Sink.foreach(println)
in ~> flow ~> out
ClosedShape
})
g.run()
Obviously being new to Scala and Akka, my unsatisfying theory so far is that using create()
of GraphDSL
creates a RunnableGraph
by passing the Builder
into it.
Why does it have to be marked as implicit
? If left away, the ~>
operators cannot be resolved anymore - even though GraphDSL.Implicits._
is explicitly imported.
implicit
has multiple use cases in Scala, one of them being the implicit classes you mention. However, there are also implicit parameters and implicit conversions. I recommend reading up on those, it's a bit much for the scope of this answer and would needlessly duplicate information. Note however that implicit classes are mostly syntactic sugar for a class with an implicit conversion, so they function the same.
If left away, the ~> operators cannot be resolved anymore - even though GraphDSL.Implicits._ is explicitly imported.
This imports the implicit conversions to FlowOps
where ~>
is actually defined. At this point Scala knows about the conversion. However to actually perform this it needs an implicit parameter b : Builder[_]
. Take a look at the conversion definition in Implicits
:
implicit def fanOut2flow[I, O](j: UniformFanOutShape[I, O])(implicit b: Builder[_]): PortOps[O]
Now you can mark any Builder[_]
as implicit and Scala will fill this parameter in for you automatically if it's missing. Removing the implicit
keyword from your Builder means that there is no longer any implicit value available to fill this parameter, which means the conversion can't happen and subsequently the method ~>
is not available.
You are however free to call the implicit conversion manually and fill in the missing parameter yourself (circumventing the whole implicit parameter functionality), but this would look very ugly/verbose in comparison:
in ~> // .. and so on
// would become
fanOut2flow(in)(builder) ~> // .. and so on