I have a method with implicits:
def f(x: String)(implicit dispatcher: ExecutionContextExecutor, mat: ActorMaterializer) = ???
And I want to create a helper method like:
def g1(y: String) = f("uri1" + y)
def g2(y: String) = f("uri2" + y)
Of course, this cannot compile as no implicits found for parameter ex: ExecutionContext for method g.
I don't want to repeat the implicits declaration in g.
So, what's the idiomatic solution for this case?
Idiomatic solution is to repeat implicit parameters.
If you repeat the same set of implicit parameters many times then idiomatic solution is to introduce your type class (or just single implicit) instead of that set of implicits and use this type class.
Not idiomatic solution is to introduce macro annotation that will generate implicit parameter section for methods.
Sometimes you can transfer implicits to some level above
class MyClass(implicit val ec: ExecutionContext) extends ExecutionContextAware {
def f(x: String) = ???
def g(y: String) = f("xxx" + y)
}
trait ExecutionContextAware {
implicit def ec: ExecutionContext
}
or
trait MyTrait extends ExecutionContextAware {
def f(x: String) = ???
def g(y: String) = f("xxx" + y)
}
object Impl extends ExecutionContextAware {
implicit def ec: ExecutionContext = ExecutionContext.Implicits.global
}
trait ExecutionContextAware {
implicit def ec: ExecutionContext
}
Could you please also give an example with typeclass?
Suppose you have multiple type classes
trait TC1[A] {
def foo = ???
}
trait TC2[A] {
def bar = ???
}
and you have to repeat them in methods
def f[A](implicit tc1: TC1[A], tc2: TC2[A]) = ???
1. Then you can introduce your type class
trait TC[A] {
def foo
def bar
}
express it via TC1, TC2, ...
object TC {
implicit def mkTC[A](implicit tc1: TC1[A], tc2: TC2[A]): TC[A] = new TC[A] {
def foo = tc1.foo
def bar = tc2.bar
}
}
and use it
def f[A](implicit tc: TC[A]) = ???
2. Alternative approach is
trait TC[A] {
implicit def tc1: TC1[A]
implicit def tc2: TC2[A]
}
object TC {
implicit def mkTC[A](implicit _tc1: TC1[A], _tc2: TC2[A]): TC[A] = new TC[A] {
implicit def tc1: TC1[A] = _tc1
implicit def tc2: TC2[A] = _tc2
}
}
def f[A](implicit tc: TC[A]) = {
import tc._
???
}
In your example with ExecutionContextExecutor, ActorMaterializer (for example following the 2nd approach) you can introduce
trait MyImplicit {
implicit def dispatcher: ExecutionContextExecutor
implicit def mat: ActorMaterializer
}
and replace
def f(x: String)(implicit dispatcher: ExecutionContextExecutor, mat: ActorMaterializer) = ???
with
def f(x: String)(implicit mi: MyImplicit) = {
import mi._
???
}
Related
I'm trying to generate instances of case class using shapeless
This works for generating instances of Foo
case class Foo(x: Int, y: String)
class Context {
val random = new Random()
}
def genInt(context: Context): Int = {
context.random.nextInt()
}
def genString(context: Context): String = {
context.random.nextString(16)
}
object ClassesToGenerators extends Poly1 {
implicit def caseInt = at[Class[Int]](_ => genInt(_))
implicit def caseString = at[Class[String]](_ => genString(_))
}
val gen = Generic[Foo]
val context = new Context()
val classes = classOf[Int] :: classOf[String] :: HNil // can't figure out how to get this hlist programmatically
val generators = classes.map(ClassesToGenerators)
gen.from(generators.zipApply(generators.mapConst(context)))
However, I'm aiming to write something reusable like
def newInstance[T] -> T:
???
which could generate instances of any case classes that takes only int and string parameters.
As mentioned in the code snippet, I'm stuck at getting a hlist of case class attribute types i.e. would like to convert case class Foo(x: Int, y: String) to classOf[Int] :: classOf[String] :: HNil. Any other approaches to this problem are also very appreciated but I'm not looking for a generic way of generating random instances of cases classes (as my use-case is different and used random generator just as an example)
IMHO, Shapeless is better used when you forget about all the fancy stuff and just focus on simple typeclass derivation using HList like this:
import shapeless.{Generic, HList, HNil, :: => :!:}
import scala.util.Random
trait Context {
def random: Random
}
object Context {
object implicits {
implicit final val global: Context = new Context {
override final val random: Random = new Random()
}
}
}
trait Generator[A] {
def generate(context: Context): A
}
object Generator {
final def apply[A](implicit ev: Generator[A]): ev.type = ev
final def generate[A](implicit ev: Generator[A], ctx: Context): A =
ev.generate(ctx)
implicit final val IntGenerator: Generator[Int] =
new Generator[Int] {
override def generate(context: Context): Int =
context.random.nextInt()
}
implicit final val StringGenerator: Generator[String] =
new Generator[String] {
override def generate(context: Context): String =
context.random.nextString(16)
}
implicit final def auto[P <: Product](implicit ev: GeneratorGen[P]): Generator[P] = ev
}
sealed trait GeneratorRepr[R <: HList] extends Generator[R]
object GeneratorRepr {
implicit final val HNilGeneratorRepr: GeneratorRepr[HNil] =
new GeneratorRepr[HNil] {
override def generate(context: Context): HNil =
HNil
}
implicit final def HConsGeneratorRepr[E, T <: HList](
implicit ev: Generator[E], tail: GeneratorRepr[T]
): GeneratorRepr[E :!: T] =
new GeneratorRepr[E :!: T] {
override def generate(context: Context): E :!: T =
ev.generate(context) :: tail.generate(context)
}
}
sealed trait GeneratorGen[P <: Product] extends Generator[P]
object GeneratorGen {
implicit final def instance[P <: Product, R <: HList](
implicit gen: Generic.Aux[P, R], ev: GeneratorRepr[R]
): GeneratorGen[P] = new GeneratorGen[P] {
override def generate(context: Context): P =
gen.from(ev.generate(context))
}
}
Which can be used like this:
import Context.implicits.global
final case class Foo(x: Int, y: String)
val result = Generator.generate[Foo]
// result: Foo = Foo(-2127375055, "鞰Ϗƨ沺㗝䚮Ⴍ욏ꖱꬮӝ闉믃雦峷")
You can see the code running here.
Using built-in Shapeless type classes you can do
import shapeless.ops.hlist.FillWith
import shapeless.{Generic, HList, Poly0}
val context = new Context()
object ClassesToGenerators extends Poly0 {
implicit val caseInt = at[Int](genInt(context))
implicit val caseString = at[String](genString(context))
}
def newInstance[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[L <: HList]()(implicit
generic: Generic.Aux[A, L],
fillWith: FillWith[ClassesToGenerators.type, L]
): A = generic.from(fillWith())
}
newInstance[Foo]() // Foo(2018031886,⮐掐禃惌ᰧ佨妞ዤࠒ훿柲籐妭蝱⻤)
i'm new to typeclass pattern and implicit in scala, below is a code snippet i did to test this pattern, but i don't know why the compareB method is not able to find implicit value for the parameter wrapper , even so i have an implicit field of type IntWrapper[Int] declared.
Does anyone have an idea how implicit are resolved in typeclass ? and why the code below does not compile ?
Thanks
trait IntWrapper[T]{
def test: Boolean
}
trait ProductComparator[T] extends Serializable{
def compare(p1 : T, p2: T): Boolean
}
object ProductComparator{
def apply[A](implicit cmp: ProductComparator[A]) : ProductComparator[A] = cmp
implicit def w: IntWrapper[Int] =
new IntWrapper[Int] {
override def test: Boolean = true
}
implicit def CompareB[T <: Product, Repr <: HList, KRepr <: HList](implicit gen: LabelledGeneric.Aux[T, Repr], keys: Keys.Aux[Repr, KRepr], wrapper: IntWrapper[Int]) : ProductComparator[T] =
new ProductComparator[T] {
override def compare(p1: T, p2: T): Boolean = {
p1.productArity == p2.productArity
}
}
}
case class Emp(a: Int, b: Int)
object Demo extends App{
val comparator = implicitly[ProductComparator[Emp]]
}
Normally implicits for type TC[A] are put either to the companion object of TC or companion object of A.
So transfer
implicit def w: IntWrapper[Int] =
new IntWrapper[Int] {
override def test: Boolean = true
}
from the companion object of ProductComparator to the companion object of IntWrapper
object IntWrapper {
implicit def w: IntWrapper[Int] =
new IntWrapper[Int] {
override def test: Boolean = true
}
}
Then the code should compile.
Alternatively you can import w as #TomerShetah proposed.
Where does Scala look for implicits?
When you define
implicit val foo: Foo = ???
def bar(implicit foo1: Foo) = ???
(in your example foo is w, bar is CompareB, Foo is IntWrapper[Int])
you shouldn't generally assume that foo1 is foo. foo is defined in the current scope and foo1 will be resolved in the scope of bar call site. This can be foo if it's there in a scope or some other implicit.
When doing implicit resolution with type parameters, why does val placement matter?
Setting abstract type based on typeclass
Reverse HList and convert to class?
The issue is scopes. In the line:
val comparator = implicitly[ProductComparator[Emp]]
The method:
def apply[A](implicit cmp: ProductComparator[A]): ProductComparator[A] = cmp
Will be called, where A is Emp. The implicit that can create that, is CompareB. CompareB Needs more implicits. The first 2, comes from imports. So they are in scope. The variable w is defined on the object ProductComparator therefore it is not in the scope where you define val comparator.
In order to add it to scope, you have few options:
Importing it with:
import ProductComparator.w
Moving implicit def w: IntWrapper[Int] to the same scope as trait IntWrapper[T], which makes:
import shapeless.ops.record.Keys
import shapeless.{HList, LabelledGeneric}
trait IntWrapper[T]{
def test: Boolean
}
implicit def w: IntWrapper[Int] =
new IntWrapper[Int] {
override def test: Boolean = true
}
trait ProductComparator[T] extends Serializable{
def compare(p1 : T, p2: T): Boolean
}
object ProductComparator{
def apply[A](implicit cmp: ProductComparator[A]) : ProductComparator[A] = cmp
implicit def CompareB[T <: Product, Repr <: HList, KRepr <: HList](implicit gen: LabelledGeneric.Aux[T, Repr], keys: Keys.Aux[Repr, KRepr], wrapper: IntWrapper[Int]) : ProductComparator[T] =
new ProductComparator[T] {
override def compare(p1: T, p2: T): Boolean = {
p1.productArity == p2.productArity
}
}
}
case class Emp(a: Int, b: Int)
object Demo extends App{
val comparator = implicitly[ProductComparator[Emp]]
}
To read more about where does Scala look for implicits you can read Daniels brilliant post.
I have the following trait:
trait Close[T]{
def close(t: T): Unit
}
object Close {
final class CloseOps[T](t: T, c: Close[T]){
def close(): Unit = c.close(t)
}
implicit def toCloseOps[T](t: T)(implicit c: Close[T]) = new CloseOps[T](t, c)
}
And its instances:
implicit val closeInputStream: Close[InputStream] = (t: InputStream) => t.close()
implicit def noOpClose[T]: Close[T] = _ => ()
My misunderstanding is if I import both of the implicits listed above I have the more specific one is used. I mean the method
def someMethod[T](t: T)(implicit c: Close[T]){
t.close()
}
and its usage
import Close._
val is: InputStream = new InputStream{
override def read() = -1
override def close() = throw new RuntimeException()
}
someMethod(is) //throws RuntimeException
So is it reliable to assume that in such a case the instance of closeInputStream instance will be used instead of noOpClose[InputStream]? Or is it common to provide sort of fallback implicit instance? Both of them are matched.
It is a common practice to provide a helper value class for accessing type classes - something like
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
implicit val intCanShow: Show[Int] =
new Show[Int] {
def show(int: Int): String = s"int $int"
}
}
In my case, I have a type class with 2 parameters. And I cannot get the value class to work (MapperOps). I keep getting "could not find implicit value for parameter mapper"
trait Mapper[T, D] {
def toDto(i: T): D
}
object Mapper {
def map[T, D](i: T)(implicit mapper: Mapper[T, D]): D = implicitly[Mapper[T, D]].toDto(i)
def apply[T, D](implicit mapper: Mapper[T, D]): Mapper[T, D] = mapper
implicit def optionMapper[T, D](implicit mapper: Mapper[T, D]): Mapper[Option[T], Option[D]] = {
new Mapper[Option[T], Option[D]] {
override def toDto(i: Option[T]): Option[D] = i.map(mapper.toDto)
}
}
implicit def seqMapper[T, D](implicit mapper: Mapper[T, D]): Mapper[Seq[T], Seq[D]] = {
new Mapper[Seq[T], Seq[D]] {
override def toDto(i: Seq[T]): Seq[D] = i.map(mapper.toDto)
}
}
// Neither works
implicit class MapperOps1[T,D](a: T) {
def toDto = Mapper[T,D].toDto(a)
}
implicit class MapperOps2[T,D](a: T) {
def toDto(implicit mapper: Mapper[T,D]) = Mapper[T,D].toDto(a)
}
implicit class MapperOps3[T,D](a: T) {
def toDto[D](implicit mapper: Mapper[T,D]): D Mapper[T,D].toDto(a)
}
}
Notice the important difference that in
implicit class ShowOps[A: Show](a: A) { ... }
you have this A : Show part, which essentially desugares into
implicit class ShowOps[A](a: A)(implicit s: Show[A]) { ... }
Since there is no neat [T : MyTypeClass]-syntax for two-parameter "Type-Pair-Classes", you have to provide the implicit Mapper as a separate
parameter to the constructor:
implicit class MapperOps1[T, D](a: T)(implicit m: Mapper[T, D]) {
def toDto = Mapper[T, D].toDto(a)
}
The following little test compiles and outputs "42":
implicit object IntToStringMapper extends Mapper[Int, String] {
def toDto(i: Int): String = i.toString
}
import Mapper._
val s: String = 42.toDto
println(s)
Alternatively, you could try it with an implicit conversion (compiler will whine at you if you don't enable this feature explicitly, and users will whine at you if you don't use this feature wisely):
class MapperOps1[T,D](a: T, mapperTD: Mapper[T, D]) {
def toDto = {
implicit val m: Mapper[T, D] = mapperTD
Mapper[T,D].toDto(a)
}
}
import scala.language.implicitConversions
implicit def wrapIntoMapperOps1[T, D]
(a: T)
(implicit m: Mapper[T, D]): MapperOps1[T, D] = new MapperOps1(a, m)
I won't comment on your two other attempts: apparently, the compiler cannot instantiate those, because it doesn't get enough information about the type parameters before it has to instantiate a wrapper.
I have the following trait:
trait CSVRowParser[A] {
def parse(row: Seq[String]): Try[A]
}
object CSVRowParser {
implicit def all[A, H <: HList](implicit gen: Generic.Aux[A, H],
read: CSVRowReader[H]): CSVRowParser[A] = new CSVRowParser[A] {
def parse(row: Seq[String]): Try[A] = {
read.from(row).map(gen.from)
}
}
def apply[A](implicit ev: CSVRowParser[A]): CSVRowParser[A] = ev
}
I have another class called CSVReader:
class CSVReader[A: CSVRowParser] {
def parse(path: String): ReaderWithFile[A] = ReaderWithFile[A](path)
case class ReaderWithFile[B: CSVRowParser](path: String) {
...
// how can I here identify the type of B?
}
}
I then do the call like this:
def apply[A: CSVRowParser] = new CSVReader[A]
val reader = apply[Address]
val withCustomConfig: Seq[Address] = reader parse "/csv-parser/address.csv" using CSVParserConfig(Pipe)
How can I get the runtime type of A inside the ReaderWithFile case class?