Scala Future strange compile error - scala

Code below is a simplified version of the real code. We "inherited" the domain model case object FutTest and case class FutTest, which we can't modify. The actual domain models are served from a Database, so I believe the Future approach is valid, but it causes problems which I don't understand.
import org.scalatest.FunSpec
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
case object FutTest {
def create(sz: Int) = { FutTest(sz) }
}
case class FutTest(size: Int)
class FutureTest extends FunSpec {
def one(v: Int): Future[FutTest] = {
Future { FutTest.create(v) }
}
def two(t: FutTest) = {
Future { FutTest.create(t.size) }
}
def compileError1: Future[FutTest] = {
one(10).map(f => two(f))
}
def compileError2: Future[FutTest] = {
for { o <- one(10) } yield (two(o))
}
}
The error messages:
[INFO] Using incremental compilation
[INFO] Compiling 7 Scala sources and 5 .. target/test-classes...
[ERROR] domain.FutureTest.scala:25: type mismatch;
found : scala.concurrent.Future[domain.FutTest]
required: domain.FutTest
[ERROR] one(10).map(f => two(f))
[ERROR] ^
[ERROR] domain/FutureTest.scala:29: type mismatch;
found : scala.concurrent.Future[domain.FutTest]
required: domain.FutTest
[ERROR] for { o <- one(10) } yield (two(o))
I tried the above code with plain Int instead of FutTest and all is fine. Why is the compiler complaining and how can we solve this without touching the existing domain.

flatMap is what you want.
one(10).flatMap(f => two(f))
or
one(10).flatMap(two)
Using for comprehension,
for { o <- one(10); t <- two(o) } yield t

One() returns a Future and two() also returns a Future so you need to flatMap instead of map. When you map to two(), your result is Future[Future[FutTest]] and needs to be flattened.
Doing
one(10).flatMap(f => two(f))
should do the trick.

Related

How do I turn a cats IO into a Effect using http4s

I've got some code that returns an IO but I need a Effect in http4s.
import cats.effect.{Effect, IO}
class Service[F[_]: Effect] extends Http4sDsl[F] {
val service: HttpService[F] = {
HttpService[F] {
case GET -> Root =>
val data: IO[String] = getData()
data.map(d => Ok(d))
}
}
}
gives
[error] found : cats.effect.IO[F[org.http4s.Response[F]]]
[error] required: F[org.http4s.Response[F]]
[error] data.map(d => Ok(d))
[error] ^
One way we can get around using a concrete IO[A] is using LiftIO[F]:
class Service[F[_]: Effect] extends Http4sDsl[F] {
val service: HttpService[F] = {
HttpService[F] {
case GET -> Root =>
getData().liftIO[F].flatMap(Ok(_))
}
}
}
LiftIO lifts will lift: IO[A] => F[A], but this yields us F[F[Response[F]. In order to get things to compile, we'll flatten on F since it has a Monad (or FlatMap) instance in cats due to our Effect context bounds requirement.
If we want more detail, this is the -Xprint:typer result:
cats.implicits.catsSyntaxFlatten[F, org.http4s.Response[F]](
cats.effect.LiftIO.apply[F](Service.this.evidence$1)
.liftIO[F[org.http4s.Response[F]]](
data.map[F[org.http4s.Response[F]]](
((d: String) => Service.this.http4sOkSyntax(Service.this.Ok)
.apply[String](d)(Service.this.evidence$1,
Service.this.stringEncoder[F](
Service.this.evidence$1, Service.this.stringEncoder$default$2[F]))))))(Service.this.evidence$1).flatten(Service.this.evidence$1)
And at the end of the world when you want to give a concrete effect, for example Service[IO], we get:
val serv: Service[cats.effect.IO] =
new Service[cats.effect.IO]()(effect.this.IO.ioConcurrentEffect)
Where ioConcurrentEffect is the Effect[IO] instance.
It seems that all the good stuff is defined at org.http4s.syntax.AllSyntax trait.

found : akka.http.scaladsl.server.StandardRoute [error] required: scala.util.Try

I am new to Scala and to akka i am trying to publish endpoint. Following compilation error is occurring.
found: akka.http.scaladsl.server.StandardRoute
[error] required: scala.util.Try[Option[com.activegrid.entities.AuthSettings]] => (akka.http.scaladsl.server.RequestContext => scala.concurrent.Future[akka.http.scaladsl.server.RouteResult])
Case class
case class AuthSettings(authType:String,authLevel:String,scope:String);
Enpoint
pathPrefix("config") {
path("settings"/"auth") {
post {
entity(as[AuthSettings]) { authSettings =>
val save: Future[AuthSettings] = persistance.persistAuthSettings(authSettings)
onComplete(save) {
complete("To insert app settings")
}
}
}
}
persistAuthSettings definition
def persistAuthSettings(authSettings: AuthSettings) : Future[AuthSettings] = Future {
//Neo4j Operations
authSettings;
}
What is going wrong in my code?
onComplete extracts the value from the future, and requires a function which operates on this value:
onComplete(save) { appSettings =>
complete("To insert app settings")
}

Futures are causing me some confused, tried flatMap identity

I am having issues trying to write a method to return a Future[Map[Int,Long]].
I was in some iteration of this getting back a Future[Future[..]]. So I tried the flatMap identity.
Please see below for my code and error messages I am getting now. I am not sure what is going on here at the moment.
def aggregate(permissions: Vector[Permission]): Map[Int, Long]
def calculate(roleProfile: RoleProfile): Future[Map[Int, Long]] = {
val roleIds = roleProfile.roles.map(r => r.id)
db.run(permissionDao.getByRoles(roleIds.toList)).map {
permissions =>
aggregate(permissions)
}
}
def generate(roleGroupId: Int): Future[Map[Int, Long]] = {
for {
roleGroup <- roleGroupService.getById(roleGroupId)
roles <- roleGroupService.getRolesByGroupId(roleGroupId)
} yield {
calculate(RoleProfile(roleGroup.get.id, roles.toSet)) //flatMap identity
}
}
I am getting an error message for method 'calculate':
type mismatch;
[error] found : scala.concurrent.Future[Map[Int,Long]]
[error] required: Map[Int,Long]
[error] calculate(RoleProfile(roleGroup.get.id, roles.toSet)) //flatMap identity
Now if remove the comments for 'flatMap identity' I get this error:
type mismatch;
[error] found : Map[Int,Long] => Map[Int,Long]
[error] required: Map[Int,Long] => scala.concurrent.Future[?]
[error] calculate(RoleProfile(roleGroup.get.id, roles.toSet)) flatMap identity
I'm very confused, how can I get this to return Future[Map[Int, Long]].
And more importantly, what is going on here that I just don't seem to understand. Please break things down if you can much appreciated.
Since calculate, like your getById etc calls, returns a Future, you should be able to simply add it into the main part of the for-comprehension, eg:
def generate(roleGroupId: Int): Future[Map[Int, Long]] = {
for {
roleGroup <- roleGroupService.getById(roleGroupId)
roles <- roleGroupService.getRolesByGroupId(roleGroupId)
profile <- calculate(RoleProfile(roleGroup.get.id, roles.toSet))
} yield { profile }
}

scrutinee is incompatible with pattern type; found : package.SomeObject required: Unit

I am trying a filesearcher program in scala.
FileChecker.scala
package fileSearcher
import sun.org.mozilla.javascript.internal.ast.Yield
class FilterChecker(filter:String) {
def matches(content: String) = content contains filter
def findMatchedFiles(fileObjects: List[IOObject]) =
for(fileObject <- fileObjects
if(fileObject.isInstanceOf[FileObject])
if(matches(fileObject.name)))
yield fileObject
}
object FilterChecker{
def apply(filter: String)=new FilterChecker(filter)
}
IOObject.scala
package fileSearcher
import java.io.File
trait IOObject {
val file:File
val name= file.getName()
}
case class FileObject(file: File)extends IOObject
case class DirectoryObject(file: File)extends IOObject
FileConverter.scala
package fileSearcher
import java.io.File
object FileConverter {
def convertToIOObject(file: File){
if(file.isDirectory()) DirectoryObject(file)
else FileObject(file)
}
}
Matcher.scala
package fileSearcher
import java.io.File
class Matcher(filter:String,rootLocation:String) {
val rootIOObject=FileConverter.convertToIOObject(new File(rootLocation))
def execute()={
val matchedFiles= rootIOObject match {
case file : FileObject if FilterChecker(filter) matches file.name =>List(file) //error 1
case directory: DirectoryObject => ??? //error 2
case _ => List()
}
matchedFiles map(iOObject => iOObject.name)
}
}
The above code gives me 2 error.
scrutinee is incompatible with pattern type; found : fileSearcher.FileObject required: Unit
scrutinee is incompatible with pattern type; found : fileSearcher.DirectoryObject required: Unit
Can anybody explain me what I am doing wrong and how can I resolve it?
Thanks
You are missing an equals sign:
def convertToIOObject(file: File) = {
^
here
Without it, the compiler assumes that the method returns Unit, which is why the match statement was confused: it can't be a FileObject or DirectoryObject if it has to be a Unit.

Scala convert Future[Option[Account]] to Future[Either[String, Option[Account]]]

I have the following methods that return futures:
db.find(uuid, accountName): Future[Option[Account]]
db.add(uuid, account): Future[Option[Account]]
I want to write a program that finds a user in the database using a future.
If not, a user entry should be added to the database.
In either case, I want to get back a Future[Either[String, Option[Account]]] object.
I am getting a compiler error when I write the following:
def add(uuid: UUID, account: Account): Future[Either[String, Option[Account]]] =
db.find(userId, account.name).map {
case None =>
db.add(userId.uuid, account).map(Right(_))
case Some(existAccount) =>
Left(s"Account already exist $existAccount")
}
Edit:
This code can`t compile with error:
Error:(77, 41) type mismatch;
found : scala.concurrent.Future[scala.util.Right[Nothing,Option[Account]]]
required: Either[String,Option[Account]]
db.add(userId, account).map(Right(_))
^
Resolved:
Solution is:
object Test extends App {
import concurrent._
import ExecutionContext.Implicits._
import duration.Duration._
type Account = String
val found = """(.+)\1""".r
def find(name: String) = name match {
case found(_*) => Future(Option(name))
case _ => Future(None)
}
def add(account: Account) = Future(Option(account * 2))
def f(account: Account): Future[Either[String, Option[Account]]] = {
find(account) flatMap {
case None => add(account) map (Right(_))
case Some(x) => Future successful Left(s"already $account")
}
}
Console println Await.result(f("bob"), Inf)
Console println Await.result(f("bobbob"), Inf)
}