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.
Related
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._
???
}
I have written this code
trait Input[F[_]] {
def read: F[String]
def write(str: String) : F[Unit]
def getName : F[String] = for {
_ <- write("What is your name")
name <- read
} yield name
}
This code doesn't compile obviously because the compiler has no way of knowing that the type F supports flatmap. So I change my code to
import scalaz._
import Scalaz._
trait Input[F[_] : Monad] {
def read: F[String]
def write(str: String) : F[Unit]
def getName : F[String] = for {
_ <- write("What is your name")
name <- read
} yield name
}
but now I get compile time error traits cannot have type parameters with context bounds.
So how can I specify constraints on my type parameter so that it always supports flatmap?
trait Input[F[_]: Monad] would create an implicit constructor parameter and traits can't have constructor parameters (until Scala 3). def testFunc[F[_]: Monad] would create an implicit parameter. For instance:
def testFunc[F[_]: Monad](arg: Int) = ???
class TestClass[F[_]: Monad] {}
Will work because it is translated to:
def testFunc[F[_]](arg: Int)(implicit ev: Monad[F]) = ???
class TestClass[F[_]](implicit val ev: Monad[F]) {}
I.e. [F[_]: Monad] is syntactic sugar for [F[_]] with implicit val ev: Monad[F]. And traits has no constructor to pass parameters until Scala 3.
For your case, if you really need to inside a trait to constraint F to a Monad for example, then:
trait Input[F[_]] {
val M: Monad[F]
def read: F[String]
def write(str: String) : F[Unit]
def getName : F[String] = M.flatMap(write("What is your name"))(_ => read)
}
I.e. you are saying to one who implements, that "you can implement Input, as soon as you have Monad[F]". Then you can use it like:
object Main extends App{
class IOInput extends Input[IO] {
override val M: Monad[IO] = Monad[IO]
override def read: IO[String] = IO("red")
override def write(str: String): IO[Unit] = IO(println(s"write: $str"))
}
val impl = new IOInput
println(impl.getName.unsafeRunSync())
}
P.S. But for me, it seems like something is wrong. You are kinda defining effects in trait Input and using them right in the same trait. Reads weird for me at least. Probably getName should be somewhere else.
What I'm trying to do is: get an implicit instance from the class name.
The main problem that I can't get an implicit instance for a class type that created at runtime.
What I have:
trait Base
case class A() extends Base
case class B() extends Base
trait Worker[T <: Base] {
def foo(t: T): Unit
}
implicit val workerA = new Worker[A] {
def foo(a: A): Unit = ??? // do some A specific work
}
implicit val workerB = new Worker[B] {
def foo(b: B): Unit = ??? // do some B specific work
}
What I want to do: somehow get an implicit instance from the class name.
trait TypeHolder {
type Typed <: Base
}
def getClassType(className: String): TypeHolder = className match {
case "A" => new TypeHolder {
type Typed = A
}
case "B" => new TypeHolder {
type Typed = B
}
}
def getWorker(typeHolder: TypeHolder)(implicit worker: Worker[typeHolder.Typed]): Worker[typeHolder.Typed] = worker
val className: String = ConfigFactory.load().getString("class-name")
val worker = getWorker(getClassType(className))
Error: could not find implicit value for parameter worker: Worker[typeHolder.Typed]
val worker = getWorker(getClassType(className))
That's impossible.
Implicit resolution is resolved at compile time: it can't be influence by a runtime value.
I'm creating custom json readers for case classes but it can't find implicit JsonReader type class for List[T] which is used in other case class.
When I checked DefaultJsonProtocol, it has implicit format for collections already;
implicit def listFormat[T :JsonFormat] = new RootJsonFormat[List[T]] {
def write(list: List[T]) = JsArray(list.map(_.toJson).toVector)
def read(value: JsValue): List[T] = value match {
case JsArray(elements) => elements.map(_.convertTo[T])(collection.breakOut)
case x => deserializationError("Expected List as JsArray, but got " + x)
}
}
Here is the simplified code;
case class Test(i: Int, d: Double)
case class ListOfTest(t: List[Test])
trait TestResultFormat extends DefaultJsonProtocol {
import CustomFormat._
implicit object TestJsonFormat extends RootJsonReader[Test] {
override def read(json: JsValue): Test = {
val jsObject = json.asJsObject
val jsFields = jsObject.fields
val i = jsFields.get("i").map(_.convertTo[Int]).getOrElse(0)
val d = jsFields.get("d").map(_.convertTo[Double]).getOrElse(0d)
Test(i, d)
}
}
implicit object ListOfTestJsonFormat extends RootJsonReader[ListOfTest] {
override def read(json: JsValue): ListOfTest = {
val jsObject = json.asJsObject
val jsFields = jsObject.fields
val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)
ListOfTest(tests)
}
}
}
Here is the errors;
Error:(230, 53) not enough arguments for method convertTo: (implicit evidence$1: spray.json.JsonReader[List[com.xx.Test]])List[com.xx.Test].
Unspecified value parameter evidence$1.
val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)
^
Error:(230, 53) Cannot find JsonReader or JsonFormat type class for List[com.xx.Test]
val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)
^
I think the problem is related to the fact that the JsonReader for List[T] in DefaultJsonProtocol is a RootJsonFormat (not a RootJsonReader), which basically means you can read it and also write it. So, when you try to read a List[Item], it's expected that you are also able to write Items. So, you could use RootJsonFormat instead and throw an exception in case you try to write it (since you don't support it). For example:
import spray.json._
implicit object TestJsonFormat extends RootJsonFormat[Test] {
override def read(json: JsValue): Test = {
val jsObject = json.asJsObject
val jsFields = jsObject.fields
val i = jsFields.get("i").map(_.convertTo[Int]).getOrElse(0)
val d = jsFields.get("d").map(_.convertTo[Double]).getOrElse(0d)
Test(i, d)
}
override def write(obj: Test): JsValue = serializationError("not supported")
}
If you are aware of a clean solution involving only the readers, please do let me know because I ran into this problem myself and couldn't find anything else.
I have learned that limitation comes from spray-json:
spray-json 's type class infrastructure is build around the (Root)JsonFormat type, not the (Root)JsonReader. So you'll indeed have to provide a "Format" even if you are just reading.
Check here.
To overcome issue; I created another trait extends RootJsonFormat instead of reader and overrides write method with basically not implemented method.
trait EmptyWriterFormat[T] extends RootJsonFormat[T] {
override def write(o: T): JsValue = ???
}
I'm trying to add an implicit value to (what I believe is) the companion object of a case class, but this implicit value is not found.
I'm trying to achieve something like the following:
package mypackage
object Main {
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = ...
serialize(out, caseClassInstance)
// the above line makes the compiler complain that there is no
// Serializer[MyCaseClass] in scope
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
...
}
}
object MyCaseClass {
// implicits aren't found here
implicit val serializer: Serializer[MyCaseClase] = ...
}
case class MyCaseClass(s: String) {
// some other methods
}
I've explicitly added the package here to show that both the MyCaseClass case class and object should be in scope. I know that the object is actually being constructed because I can get this to compile if I add
implicit val serializer = MyCaseClass.serializer
to main (though notably not if I add import MyCaseClass.serializer).
I'm concerned that the MyCaseClass object is not actually a companion of the case class, because if I explicitly define apply and unapply on the object and then attempt to call MyCaseClass.apply("string") in main, the compiler gives the following error:
ambiguous reference to overloaded definition,
both method apply in object MyCaseClass of type (s: String)mypackage.MyCaseClass
and method apply in object MyCaseClass of type (s: String)mypackage.MyCaseClass
match argument types (String)
val a = InputRecord.apply("string")
^
If it's not possible to take this approach, is there a way to use type classes with case classes without creating an implicit value every time it must be brought into scope?
EDIT: I'm using scala 2.10.3.
EDIT 2: Here's the example fleshed out:
package mypackage
import java.io.{DataOutput, DataOutputStream}
object Main {
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = new DataOutputStream(System.out)
serialize(out, caseClassInstance)
// the above line makes the compiler complain that there is no
// Serializer[MyCaseClass] in scope
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
implicitly[Serializer[T]].write(out, t)
}
}
object MyCaseClass {
// implicits aren't found here
implicit val serializer: Serializer[MyCaseClass] = new Serializer[MyCaseClass] {
override def write(out: DataOutput, t: MyCaseClass): Unit = {
out.writeUTF(t.s)
}
}
}
case class MyCaseClass(s: String) {
// some other methods
}
trait Serializer[T] {
def write(out: DataOutput, t: T): Unit
}
This actually compiles, though. I am getting this issue when using Scoobi's WireFormat[T] instead of Serializer, but can't provide a concise, runnable example due to complexity and the Scoobi dependency. I will try to create a more relevant example, but it seems as though the issue is not as general as I thought.
It turns out that the type class instances actually need to be implicit values, rather than objects. The MyCaseClass object above works because its serializer is assigned to an implicit value. However, this implementation
object MyCaseClass {
implicit object MyCaseClassSerializer extends Serializer[MyCaseClass] {
override def write(out: DataOutput, t: MyCaseClass): Unit = {
out.writeUTF(t.s)
}
}
}
fails with the error
Main.scala:9: error: could not find implicit value for evidence parameter of type mypackage.Serializer[mypackage.MyCaseClass]
serialize(out, caseClassInstance)
^
In my real code, I was using an auxiliary function to generate the Serializer[T] (see https://github.com/NICTA/scoobi/blob/24f48008b193f4e87b9ec04d5c8736ce0725d006/src/main/scala/com/nicta/scoobi/core/WireFormat.scala#L137). Despite the function having its own explicit return type, the type of the assigned value was not being inferred correctly by the compiler.
Below is the full example from the question with such a Serializer-generator.
package mypackage
import java.io.{DataOutput, DataOutputStream}
object Main {
import Serializer._
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = new DataOutputStream(System.out)
serialize(out, caseClassInstance)
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
implicitly[Serializer[T]].write(out, t)
}
}
object MyCaseClass {
import Serializer._
// does not compile without Serializer[MyCaseClass] type annotation
implicit val serializer: Serializer[MyCaseClass] =
mkCaseSerializer(MyCaseClass.apply _, MyCaseClass.unapply _)
}
case class MyCaseClass(s: String)
trait Serializer[T] {
def write(out: DataOutput, t: T): Unit
}
object Serializer {
// does not compile without Serializer[String] type annotation
implicit val stringSerializer: Serializer[String] = new Serializer[String] {
override def write(out: DataOutput, s: String): Unit = {
out.writeUTF(s)
}
}
class CaseClassSerializer[T, A : Serializer](
apply: A => T, unapply: T => Option[A]) extends Serializer[T] {
override def write(out: DataOutput, t: T): Unit = {
implicitly[Serializer[A]].write(out, unapply(t).get)
}
}
def mkCaseSerializer[T, A : Serializer]
(apply: A => T, unapply: T => Option[A]): Serializer[T] =
new CaseClassSerializer(apply, unapply)
}
This related, simple code below prints 1.
object A{
implicit def A2Int(a:A)=a.i1
}
case class A(i1:Int,i2:Int)
object Run extends App{
val a=A(1,2)
val i:Int=a
println(i)
}