HI!!!!!
TODAY I WILL MAKE INSANE DI USING SCALA THAT YOU WILL HATE!!! ZIO DOES IT BETTER, BUT ZIO SUCKS FOR OTHER REASONS!!!!
OK, LETS GO!!!
import cats.Monad
import scala.reflect.ClassTag
object DiMoreLikeDontInjectthings extends App {
trait SomeTrait[F[_]] {
def someFunc: F[Unit]
def someOtherFunc(withParam: String): F[Int]
}
object SomeTrait {
def apply[F[_]: SomeTrait]: SomeTrait[F] = implicitly
}
case class BigConfig(smallConfig: SmallConfig)
case class SmallConfig(value1: String)
object SmallConfig {
implicit def smallConfig(implicit bigConfig: BigConfig): SmallConfig = bigConfig.smallConfig
}
class ProductionTrait[F[_]: Monad](config: SmallConfig) extends SomeTrait[F] {
println("initiating production")
override def someFunc: F[Unit] = Monad[F].pure(println("using production"))
override def someOtherFunc(withParam: String): F[Int] = ???
}
object ProductionTrait {
implicit def productionTrait[F[_]: Monad](implicit smallConfig: SmallConfig): ProductionTrait[F] =
new ProductionTrait[F](smallConfig)
}
class Stub[F[_]: Monad] extends SomeTrait[F] {
println("initiating stub")
override def someFunc: F[Unit] = Monad[F].pure(println("using stub"))
override def someOtherFunc(withParam: String): F[Int] = ???
}
object Stub {
implicit def stub[F[_]: Monad]: Stub[F] =
new Stub[F]
}
def usingTrait[F[_]: SomeTrait] = SomeTrait[F].someFunc
val prodCode = {
implicit val bigConfig = BigConfig(SmallConfig("value 1"))
import SmallConfig._
import ProductionTrait.productionTrait
println("RUNNING PROD CODE")
usingTrait[Option]
usingTrait[Option]
println()
}
val stubCode = {
implicit val bigConfig = BigConfig(SmallConfig("value 1"))
import Stub._
println("RUNNING STUB CODE")
usingTrait[Option]
usingTrait[Option]
println()
}
object ProductionTrait2 {
private var productionTraitInstances: Map[ClassTag[_], Any] = Map.empty
implicit def productionTrait[F[_] : Monad](implicit smallConfig: SmallConfig, classTag: ClassTag[F[_]]): ProductionTrait[F] = {
productionTraitInstances.get(classTag) match {
case Some(value) => value.asInstanceOf[ProductionTrait[F]]
case None =>
val pt = new ProductionTrait[F](smallConfig)
productionTraitInstances = productionTraitInstances + (classTag -> pt)
pt
}
}
}
val prodCodeUsingASinglePT = {
implicit val bigConfig = BigConfig(SmallConfig("value 1"))
import SmallConfig._
import ProductionTrait2._
println("RUNNING PROD CODE, BUT IT DOESNT INITIATE PROD EVERY TIME")
usingTrait[Option]
usingTrait[Option]
usingTrait[Option]
usingTrait[Option]
println()
}
}
running this code returns the following output:
RUNNING PROD CODE
initiating production
using production
initiating production
using production
RUNNING STUB CODE
initiating stub
using stub
initiating stub
using stub
RUNNING PROD CODE, BUT IT DOESNT INITIATE PROD EVERY TIME
initiating production
using production
using production
using production
using production