Implicit val from context case class - scala

I have a case class:
case Context(tracker: Tracker)
I have a processor class with a get def, that expects an implicit parameter of Tracker defined as:
class Processor(){
def get(id: String)(implicit tracker: Tracker): Unit
}
and I have my calling class:
class repo(process: Processor){
def get(id: String)(implicit ctx : Context): Unit{
process.get(id)
}
}
Is there an easy way for my to map from context -> Tracker? I've been trying to use an implicit def in the companion of 'repo' but am still seeing 'no implicit val available' for the Tracker when calling process.get(id)

You can define implicit in the scope
implicit def ifContextThenTracker(implicit c: Context): Tracker = c.tracker
I've been trying to use an implicit def in the companion of 'repo' but am still seeing 'no implicit val available' for the Tracker when calling process.get(id)
Please see rules of implicit resolution in Where does Scala look for implicits?
You can put ifContextThenTracker into companion object of Tracker if you have access to it. Otherwise you can import implicit.

Related

Extending an object with a trait which needs implicit member

I'm trying to have a code like below:
object MetaData extends CacheParams{}
So, since CacheParams needs implicit val p:Parameters, I tried:
object MetaData (implicit val p: Parameters) extends CacheParams
But it seems that I can't pass arguments to an object.
( because it gives error:traits or objects may not have parameters)
And if I don't pass any arguments it will give compile error that:
[error]: object creation impossible, since value p in trait CacheParams of type Parameters is not defined
I have no idea how to make this works. There were a few similar questions, but none of their answers solved my problem. Any help would be really appreciated.
Thanks a lot.
If I guessed the definition of CacheParams correctly
trait Parameters
trait CacheParams {
implicit val p: Parameters
}
then you should: (1) replace the object
object MetaData /*(implicit val p: Parameters)*/ extends CacheParams
//object creation impossible. Missing implementation for:
// implicit val p: Parameters // inherited from trait CacheParams
with a class
class MetaData(implicit val p: Parameters) extends CacheParams
or (2) implement the implicit inside the object
object MetaData extends CacheParams {
override implicit val p: Parameters = new Parameters {}
}
or
implicit val params: Parameters = new Parameters {} // suppose an implicit is in current scope
object MetaData extends CacheParams {
override implicit val p: Parameters = {
val p = ??? // hiding above p to avoid ambiguous implicits, null or NPE, see (*) below
implicitly[Parameters]
}
}
(*) NullPointerException on implicit resolution
In (1) you're defining/resolving implicit now in current scope. In (2) you postpone resolving implicit till instantiating the class (resolving implicit in the scope of class constructor call site).
See also Pass implicit parameter through multiply objects
Yeah that would solve my problem. But I wanted to keep the object's body clean and decoupled from the configuration in Parameters, like the classes' bodies that accept the p: Parameters.
If in (1) you want to decouple the object from "the configuration in Parameters" you can try to introduce a trait (ParamsMaterializer):
object MetaData extends CacheParams with ParamsMaterializer
trait ParamsMaterializer {
implicit val p: Parameters = new Parameters {}
}
or
implicit val params: Parameters = new Parameters {} // suppose an implicit is in current scope
object MetaData extends CacheParams with ParamsMaterializer
trait ParamsMaterializer {
implicit val p: Parameters = {
val p = ???
implicitly[Parameters]
}
}

Provided implicit reader/writer for case class not found

I'm trying to write a nice generic persistence service with one implementation for mongo using Reactive Mongo and I'm struggling with providing the implicit reader/writer for my record class children. Here's the code.
First the base record class (each persisted record must implement it.
abstract class Record {
val _id: BSONObjectID = BSONObjectID.generate()
}
Second one record child case class (very simple) with its writer/reader (both possible way to do it, Macros vs custom in comment)
case class TestRecord() extends Record {}
object TestRecord {
// implicit object TestRecordWriter extends BSONDocumentWriter[TestRecord] {
// def write(testRecord: TestRecord): BSONDocument = BSONDocument()
// }
//
// implicit object TestRecordReader extends BSONDocumentReader[TestRecord] {
// def read(doc: BSONDocument): TestRecord = TestRecord()
// }
implicit def reader = Macros.reader[TestRecord]
implicit def writer = Macros.writer[TestRecord]
}
And then the service itself
class MongoPersistenceService[R <: Record] #Inject()()
(implicit ec: ExecutionContext, tag: ClassTag[R]) {
val collectionName: String = tag.runtimeClass.getSimpleName
def db: Future[DefaultDB] = MongoConnectionWrapper.getMongoConnection("mongodb://127.0.0.1", "27017")
.flatMap(_.database("testDb"))
def collection: Future[BSONCollection] = db.map(_.collection(collectionName))
def persist(record: R): Future[Unit] = {
collection.flatMap(_.insert(record)).map(_ => {})
}
def read(id: BSONObjectID): Future[R] = {
for {
coll <- collection
record <- coll.find(BSONDocument("_id" -> id)).one[R].mapTo[R]
} yield record
}
}
And here's my failing test:
import scala.concurrent.ExecutionContext.Implicits.global
class MongoPersistenceServiceSpec extends WordSpec with Matchers with BeforeAndAfter {
val persistenceService = new MongoPersistenceService[TestRecord]()
"persist" when {
"called" should {
"succeeds when passing a not persisted record" in {
val testRecord = TestRecord()
persistenceService.persist(testRecord)
val persistedRecord = Await.result(persistenceService.read(testRecord._id), Duration(1000, "millis"))
assert(persistedRecord.eq(testRecord))
}
}
}
}
Compiler complains with following messages:
Error:(33, 32) could not find implicit value for parameter writer: reactivemongo.bson.BSONDocumentWriter[R]
collection.flatMap(_.insert(record)).map(_ => {})
Error:(33, 32) not enough arguments for method insert: (implicit writer: reactivemongo.bson.BSONDocumentWriter[R], implicit ec: scala.concurrent.ExecutionContext)scala.concurrent.Future[reactivemongo.api.commands.WriteResult].
Unspecified value parameters writer, ec.
collection.flatMap(_.insert(record)).map(_ => {})
Error:(39, 57) could not find implicit value for parameter reader: reactivemongo.bson.BSONDocumentReader[R]
record <- coll.find(BSONDocument("_id" -> id)).one[R].mapTo[R]
Error:(39, 57) not enough arguments for method one: (implicit reader: reactivemongo.bson.BSONDocumentReader[R], implicit ec: scala.concurrent.ExecutionContext)scala.concurrent.Future[Option[R]].
Unspecified value parameters reader, ec.
record <- coll.find(BSONDocument("_id" -> id)).one[R].mapTo[R]
Anybody has a idea what I might be missing?
I'm still new to scala so help me find the issue in here.
I already tried writing custom BSONWriter/BSONReader instead of the BSONDocumentWriter/BSONDocumentReader provided here without success.
In short, Scala doesn't search everywhere throughout your code for implicits. They need to be brought into scope, either through imports, passing them as parameters, or, as I would suggest here, through a context bound:
class MongoPersistenceService[R <: Record : BSONDocumentReader : BSONDocumentWriter]
This is a kind of short hand for (a) requiring that an implicit BSONDocumentReader[R] (and writer) can be found at the time that the class is constructed with a specific R, and (b) bringing those implicits into scope within the class's implementation so they can be implicitly passed to other methods like insert.
In order to fulfill that new requirement (a) you may have to import TestRecord._ within your test.
Your persist function doesn't have access to the fact that you have defined those implicit functions. The signature should be something like this:
def persist(record: R)(implicit def writer: BSONDocumentWriter[R]): Future[Unit]
And wherever you call persist and pass a TestRecord make sure that the implicit functions are in scope.

Scope of Traits

I am learning Scala and Akka and I came across an example that confused me. The following code sample was in 1 file.
class RestApi(system: ActorSystem, timeout: Timeout) extends RestRoutes {
implicit val requestTimeout = timeout
implicit def executionContext = system.dispatcher
def createBoxOffice = system.actorOf(BoxOffice.props, BoxOffice.name)
}
trait BoxOfficeApi {
import BoxOffice._
def createBoxOffice(): ActorRef
implicit def executionContext: ExecutionContext
implicit def requestTimeout: Timeout
lazy val boxOffice = createBoxOffice()
// Uninteresting methods here
}
The part that confuses me is the createBoxOffice() call in the BoxOfficeAPI trait. It clearly states that the BoxOfficeAPI has a function which will return an ActorRef. However the implementation for that function is located in the RestApi class which doesn't have any reference to the trait.
How is it possible that the trait can access this method? What is the scope of a trait?
How is it possible that the trait can access this method?
I think you're missing the fact that the trait itself has an abstract method called createBoxOffice:
def createBoxOffice(): ActorRef
Which is why it has such a method in scope. It has nothing to do with the declaration of RestApi. Whoever mixes in this trait will have to implement that said method. That means, for example, that if the RestApi class decides to mix in BoxOfficeApi, it already has an implementation available which it will use. For example:
class Baz extends Foo {
override def quuux(): Unit = println("quuux")
}
trait Foo {
def quuux(): Unit
}

Why does an implicit object have higher precedence than an implicit val in Scala companion objects?

I have been playing around with this small example to try to get a better overview of how scala resolves implicits. I just discovered a difference between declaring an implicit object and an implicit val in the companion object.
The type class named "Evidence[-B]" in the example is contravariant; e.g. an Evidence[Base] can be used where a Evidence[Derived] is required.
I have tried to compile the code below with Scala 2.11.7:
trait Evidence[-B] {
def hello(input: B): String
}
trait Base
object Base {
implicit object BaseEvidence extends Evidence[Base] {
override def hello(input: Base): String = "Evidence[Base] from implicit object"
}
}
class Derived extends Base
object Derived {
implicit val derivedEvidence: Evidence[Derived] = new Evidence[Derived] {
override def hello(input: Derived): String = "Evidence[Derived] from implicit val"
}
}
object Main extends App {
def hello[A](input: A)(implicit ev: Evidence[A]): Unit = {
println(ev.hello(input))
}
hello(new Derived)
}
However, the compiler gives an error "ambiguous implicit values":
Error:(24, 8) ambiguous implicit values:
both object BaseEvidence in object Base of type Base.BaseEvidence.type
and value derivedEvidence in object Derived of type => Evidence[Derived]
match expected type Evidence[Derived]
hello(new Derived)
^
From my understanding of the implicit resolution rules, the companion object of Derivedshould be searched first; then the companion object of the base class Base.
When changing the implicit val derivedEvidence to an implicit object, the code compiles:
object Derived {
implicit object DerivedEvidence extends Evidence[Derived] {
override def hello(input: Derived): String = "Evidence[Derived] from implicit object"
}
What is the reason for this behavior?

How to fix this typeclass example?

This is a follow-up to my previous question:
Suppose I create the following test converter.scala:
trait ConverterTo[T] {
def convert(s: String): Option[T]
}
object Converters {
implicit val toInt: ConverterTo[Int] =
new ConverterTo[Int] {
def convert(s: String) = scala.util.Try(s.toInt).toOption
}
}
class A {
import Converters._
def foo[T](s: String)(implicit ct: ConverterTo[T]) = ct.convert(s)
}
Now when I tried to call foo in REPL it fails to compile:
scala> :load converter.scala
Loading converter.scala...
defined trait ConverterTo
defined module Converters
defined class A
scala> val a = new A()
scala> a.foo[Int]("0")
<console>:12: error: could not find implicit value for parameter ct: ConverterTo[Int]
a.foo[Int]("0")
^
import Converters._ in class A does not cut it. You can remove it and the code will still compile. The moment the compiler needs to find in actual implicit is not in class A, where foo is just declared.
The compiler needs to find a ConverterTo[Int] in implicit scope at the moment you call a.foo[Int](..) that is in the REPL. So this is where the import needs to be.
Had object Converters and trait ConverterTo been named the same (so there would be a companion object) the import would not be needed.