OptionT[Future[_], A] transformer needs implicit Functor[Future] in scope. But if evidence is moved to another file that doesn't have implicit ExecutionContext the compiler fails with error Cannot find an implicit ExecutionContext.. Is it possible to write a code that wouldn't have evidence definitions all over the place and will use ExecutionContext that's available at invocation of OptionT?
import scala.concurrent.{Await, Future}
import scalaz._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
object Hello {
implicit val ev = new Functor[scala.concurrent.Future] {
override def map[A, B](fa: Future[A])(f: (A) => B): Future[B] = fa.map(f)
}
def main(args: Array[String]): Unit = {
val task: Future[Option[String]] = Future { Some("hello") }
val scream = (for( message <- OptionT(task)) yield message.toUpperCase()).run
val msg = Await.result(scream, 10.seconds)
println(msg.get)
}
}
Have the evidence require the execution context:
implicit def ev (implicit ec: ExecutionContext) =
new Functor[scala.concurrent.Future] {
override def map[A, B](fa: Future[A])(f: (A) => B): Future[B] = fa.map(f)
}
This way the execution context need only be provided at invocation.
Related
Im trying to create a Generic Class in Scala so I can create a repository for different collection without repeating myself.
The problem is that if I do it as a Generic Class(as in this example) I get a problem in this line:
val codecRegistry = fromRegistries(fromProviders(classOf[T]), DEFAULT_CODEC_REGISTRY)
Expected Class but Found [T]
But if I change T for any other class (lets say User) in all the code it works.
This is my class:
package persistence.repository.impl
import akka.stream.Materializer
import akka.stream.alpakka.mongodb.scaladsl.{MongoSink, MongoSource}
import akka.stream.scaladsl.{Sink, Source}
import akka.{Done, NotUsed}
import com.mongodb.reactivestreams.client.MongoClients
import constants.MongoConstants._
import org.bson.codecs.configuration.CodecRegistries.{fromProviders, fromRegistries}
import org.mongodb.scala.MongoClient.DEFAULT_CODEC_REGISTRY
import org.mongodb.scala.bson.codecs.Macros._
import org.mongodb.scala.model.Filters
import persistence.entity.{ProductItem}
import persistence.repository.Repository
import scala.concurrent.{ExecutionContext, Future}
class UserMongoDatabase[T](implicit materializer: Materializer,
executionContext: ExecutionContext)
extends Repository[T] {
val codecRegistry = fromRegistries(fromProviders(classOf[T]), DEFAULT_CODEC_REGISTRY)
val client = MongoClients.create(HOST)
val db = client.getDatabase(DATABASE)
val requestedCollection = db
.getCollection(USER_COLLECTION, classOf[T])
.withCodecRegistry(codecRegistry)
val source: Source[T, NotUsed] =
MongoSource(requestedCollection.find(classOf[T]))
val rows: Future[Seq[T]] = source.runWith(Sink.seq)
override def getAll: Future[Seq[T]] = rows
override def getById(id: AnyVal): Future[Option[T]] = rows.map {
list =>
list.filter {
user => user.asInstanceOf[ {def _id: AnyVal}]._id == id
}.headOption
}
override def getByEmail(email: String): Future[Option[T]] = rows.map {
list =>
list.filter {
user => user.asInstanceOf[ {def email: AnyVal}].email == email
}.headOption
}
override def save(obj: T): Future[T] = {
val source = Source.single(obj)
source.runWith(MongoSink.insertOne(requestedCollection)).map(_ => obj)
}
override def delete(id: AnyVal): Future[Done] = {
val source = Source.single(id).map(i => Filters.eq("_id", id))
source.runWith(MongoSink.deleteOne(requestedCollection))
}
}
This is my repository trait:
package persistence.repository
import akka.Done
import scala.concurrent.Future
trait Repository[T]{
def getAll: Future[Seq[T]]
def getById(id: AnyVal): Future[Option[T]]
def save(user: T): Future[T]
def delete(id: AnyVal): Future[Done]
def getByEmail(email:String): Future[Option[T]]
}
As said in the comments, this is the perfect example of usage of ClassTag in Scala. It allow to retain the actual class of a generic/parameterized class.
class DefaultMongoDatabase[T](implicit ..., ct: ClassTag[T])
extends Repository[T] {
val codecRegistry = fromRegistries(fromProviders(ev.runtimeClass), ...)
(You can move the classtag logic in the trait if you want.)
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 was trying to produce a small macro to isolate another problem that I was having and started running into this compile-time error.
Error:scalac:
Unexpected tree in genLoad: test.MacroTest$Baz.type/class scala.reflect.internal.Trees$TypeTree at: source-/Users/jpatterson/test/src/test/scala/test/MacroTest.scala,line-5,offset=114
while compiling: /Users/jpatterson/test/src/test/scala/test/MacroTest.scala
during phase: jvm
library version: version 2.13.0-RC1
compiler version: version 2.13.0-RC1
reconstructed args: -deprecation -Vimplicits -language:higherKinds -language:implicitConversions -language:postfixOps -classpath ... (cut)
last tree to typer: Literal(Constant(test.MacroTest.MacroTest$Baz.type))
tree position: line 4 of /Users/jpatterson/test/src/test/scala/test/MacroTest.scala
tree tpe: Class(classOf[test.MacroTest$Baz$])
symbol: null
call site: constructor MacroTest$$anon$1 in package test
== Source file context for tree position ==
1 package test
2
3 object MacroTest {
4 case class Baz(x: Int, y: Int)
5 implicit def bazRead: Read[Baz] = Read.readFor[Baz]
6
7 def main(args: Array[String]): Unit = {
I started working with scala 2.12.8. I tried switching to 2.13.0-RC1 just to see if it was something that was already fixed. It fails the same with both versions of scala.
The macro code:
package test
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
trait Read[A] {
def read(in: String): A
}
object Read {
implicit def intRead = new Read[Int] {
override def read(in: String): Int = in.toInt
}
def CaseClassReadImpl[A: c.WeakTypeTag](c: Context): c.Expr[Read[A]] = {
import c.universe._
val aType = weakTypeOf[A]
val params = aType.decls.collect {
case m: MethodSymbol if m.isCaseAccessor => m
}.toList
val paramList = params.map(param => q"Read.read[${param.typeSignature}](in)")
val src = q"""
new Read[$aType] {
def read(in: String) = ${aType.companion}.apply(..$paramList)
}
"""
println(src)
c.Expr[Read[A]](src)
}
def readFor[A]: Read[A] = macro CaseClassReadImpl[A]
def read[A](in: String)(implicit A: Read[A]): A = A.read(in)
}
The code that exercises it:
package test
object MacroTest {
case class Baz(x: Int, y: Int)
implicit def bazRead: Read[Baz] = Read.readFor[Baz]
def main(args: Array[String]): Unit = {
println(Read.read[Baz]("4"))
}
}
Compiling the second block causes the error above.
I was expecting this to compile correctly. I put that println into the macro definition so that I could just grab the code and try to compile that. When I add that to the second block, it compiles fine. I can even replace bazRead's value with it and everything works as expected: it prints out Baz(4,4).
Regarding your macro, you're trying to splice a type (aType.companion) into a position where a term is expected (a tpe: Type is transformed into TypeTree(tpe)).
Try to replace ${aType.companion} with ${aType.typeSymbol.companion}.
For deriving type classes it's better to use Shapeless, Magnolia or Scalaz-deriving than raw macros.
For example in Shapeless Read can be derived as follows
import shapeless.{Generic, HList, HNil, ::}
trait Read[A] {
def read(in: String): A
}
object Read {
implicit def intRead: Read[Int] = _.toInt
implicit def hNilRead: Read[HNil] = _ => HNil
implicit def hConsRead[H, T <: HList](implicit r: Read[H], r1: Read[T]): Read[H :: T] =
in => r.read(in) :: r1.read(in)
implicit def caseClassRead[A, L <: HList](implicit gen: Generic.Aux[A, L], r: Read[L]): Read[A] =
in => gen.from(r.read(in))
def read[A](in: String)(implicit A: Read[A]): A = A.read(in)
}
case class Baz(x: Int, y: Int)
Read.read[Baz]("123") // Baz(123,123)
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.
I would like to write a method which would accept RDD and Seq without having to duplicate my code.
def myMethod[F[_]](input: F[InputClass]): F[OutputClass] = {
// do something here like
input.map{ i =>
// transformed input OutputClass
}
}
F could be Seq or RDD since they both have the method map implemented.
For more unique method like count or cache can I make the Seq do nothing for cache and use length for count?
What you want is a Type Class.
If you only need map and flatMap methods, I would recommend you to use a Monad (maybe the Cats one) and provide a the implementation for RDD.
Now, if you want more methods, you can implement your own Type Class.
import scala.language.higherKinds
trait DataCollection[F[_]] {
def map[A, B](col: F[A])(f: A => B): F[B]
def cache[A](col: F[A]): F[A]
def count[A](col: F[A]): Long
}
object DataCollection {
implicit val RddDataCollection: DataCollection[RDD] = new DataCollection[RDD] {
override def map[A, B](rdd: RDD[A])(f: A => B): RDD[B] = rdd.map(f)
override def cache[A](rdd: RDD[A]): RDD[A] = rdd.cache()
override def count[A](rdd: RDD[A]): Long = rdd.count()
}
implicit val SeqDataCollection: DataCollection[Seq] = new DataCollection[Seq] {
override def map[A, B](seq: Seq[A])(f: A => B): Seq[B] = seq.map(f)
override def cache[A](seq: Seq[A]): Seq[A] = seq
override def count[A](seq: Seq[A]): Long = seq.length
}
implicit class Ops[F[_], A](val col: F[A]) extends AnyVal {
#inline
def map[B](f: A => B)(implicit DC: DataCollection[F]): F[B] = DC.map(col)(f)
#inline
def cache()(implicit DC: DataCollection[F]): F[A] = DC.cache(col)
#inline
def count()(implicit DC: DataCollection[F]): Long = DC.count(col)
}
}
def myGenericMethod[F[_]: DataCollection, T](col: F[T]): Long = {
import DataCollection.Ops
col.map(x => x).cache().count()
}