I am trying to find an available slug in mongodb using Play2 and reactivemongo.
I came up with the following recursive method.
private def findSlug(base: String, index: Int): String = {
val slug: String = Slug({
base + "-" + index
})
for {
user <- findOne(BSONDocument("slug" -> slug))
} yield {
user match {
case None => slug
case Some(user) => findSlug(base, index+1)
}
}
}
I get the following error
found : scala.concurrent.Future[String]
required: String
user <- findOne(BSONDocument("slug" -> slug))
^
I played around a lot with changing return types, mapping the result of the yield, etc. but somehow I think there might be a far simpler, concise and correct solution.
It all boils down to having a recursive function that calls another asynchronous function I think.
If I change the return type of findSlug to Future[String] I get
[error] found : scala.concurrent.Future[String]
[error] required: String
[error] case Some(user) => findSlug(base, index+1)
[error] ^
What would be the correct and idiomatic solution?
I personally think that making the return type a Future[String] is the right way to go - it means you can keep that whole "Reactive", monadic, chain-of-Futures thing going for as long as possible (and with Play 2, that can be all the way to the Controller level - awesome).
I'm assuming that your findOne() method is just a wrapper for some Reactive Mongo query that will return a Future[Option[T]] at some point?
With that in mind, the only real problem is that there are differing levels of Futurey-ness coming from your two different cases.
Here's what I came up with. It works; is it idiomatic? You tell me ...
private def findSlug(base: String, index: Int): Future[String] = {
// Slug stuff omitted
findOne(BSONDocument("slug" -> slug)).flatMap { _ match {
case None => Future.successful(slug)
case Some(_) => findSlug(base, index+1)
}
}
}
Related
I’m a new scala developer kind of bogged down with a type problem. Sometimes I’m still tripped up by handling futures, and I think this is one of those times. This section of code…
// do some stuff with a collection of List[Future[ClientArticle]]
Future.sequence(listFutureClonedArticles).map( clonedArticles =>
for {
// create persistent records of the cloned client articles, and discard the response
_ <- clonedArticles.map(clonedArticle => clientArticleDAO.create(clonedArticle))
// add cloned articles to a batch of articles, and discard the response
_ <- batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id))
} yield {
// ultimately just return the cloned articles
clonedArticles
}
)
… is producing this compiler error:
[error] /.../app/services/BatchServiceAPI.scala:442: type mismatch;
[error] found : scala.concurrent.Future[List[model.ClientArticle]]
[error] required: scala.collection.GenTraversableOnce[?]
[error] _ <- batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id))
[error] ^
The arguments to addArticlesToExistingBatch() appear to be the correct type for the method signature:
/** Adds a list of id's to a batch by it's database ID. */
def addArticlesToExistingBatch(batchId: ID, articleIds: List[ID])(implicit ec: ExecutionContext): Future[Return]
Of course, I might be misunderstanding how a for comprehension works too. I don’t understand how an error can occur at the <- operator, nor how/why there would be type expectations at that point.
Can anyone help me understand what needs to be done here?
=== 21 minutes later... ===
Interesting. When I stop using the for comprehension and break these out into two separate maps, it compiles.
// create cloned client articles
Future.sequence(listFutureClonedArticles).map(clonedArticles =>
clonedArticles.map(clonedArticle => clientArticleDAO.create(clonedArticle)))
// add cloned articles to destination batch
Future.sequence(listFutureClonedArticles).map(clonedArticles =>
batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id)))
So yeah, I guess I still don't quite understand for-comprehensions. I thought they could be used to roll up several Future operations. Why doesn't that work in this scenario
for comprehension is a combination of flatMap and map. Every line with <- is converted into a flatMap but the last line which is converted to a map.
So, you code
for {
// create persistent records of the cloned client articles, and discard the response
_ <- clonedArticles.map(clonedArticle => clientArticleDAO.create(clonedArticle))
// add cloned articles to a batch of articles, and discard the response
_ <- batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id))
} yield {
// ultimately just return the cloned articles
clonedArticles
}
is converted to
clonedArticles.map(clonedArticle => clientArticleDAO.create(clonedArticle)).flatMap { _ =>
batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id)).map { _ =>
clonedArticles
}
}
as clonedArticles is a List and the signature for flatMap for the list is
final override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = ???
If you look at the parameter required by flatMap it needs a function A => GenTraversableOnce but in your function you are passing a function A => Future that is the problem.
I have tried to imitate your problem with simple functions you can try that:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
val listOfFuture: List[Future[Int]] = (1 to 10).map(Future(_)).toList
def f(i: List[Int]): Future[String] = Future(s"very complex logic: ${i.sum}")
def create(i: Int): Future[Unit] = Future(println(s"creating something complex: $i"))
Future.traverse(listOfFuture){ futureX =>
for {
x <- futureX
_ <- create(x)
} yield x
}.flatMap(f)
Scala gives the ability to unpack a tuple into multiple local variables when performing various operations, for example if I have some data
val infos = Array(("Matt", "Awesome"), ("Matt's Brother", "Just OK"))
then instead of doing something ugly like
infos.map{ person_info => person_info._1 + " is " + person_info._2 }
I can choose the much more elegant
infos.map{ case (person, status) => person + " is " + status }
One thing I've often wondered about is how to directly unpack the tuple into, say, the arguments to be used in a class constructor. I'm imagining something like this:
case class PersonInfo(person: String, status: String)
infos.map{ case (p: PersonInfo) => p.person + " is " + p.status }
or even better if PersonInfo has methods:
infos.map{ case (p: PersonInfo) => p.verboseStatus() }
But of course this doesn't work. Apologies if this has already been asked -- I haven't been able to find a direct answer -- is there a way to do this?
I believe you can get to the methods at least in Scala 2.11.x, also, if you haven't heard of it, you should checkout The Neophyte's Guide to Scala Part 1: Extractors.
The whole 16 part series is fantastic, but part 1 deals with case classes, pattern matching and extractors, which is what I think you are after.
Also, I get that java.lang.String complaint in IntelliJ as well, it defaults to that for reasons that are not entirely clear to me, I was able to work around it by explicitly setting the type in the typical "postfix style" i.e. _: String. There must be some way to work around that though.
object Demo {
case class Person(name: String, status: String) {
def verboseStatus() = s"The status of $name is $status"
}
val peeps = Array(("Matt", "Alive"), ("Soraya", "Dead"))
peeps.map {
case p # (_ :String, _ :String) => Person.tupled(p).verboseStatus()
}
}
UPDATE:
So after seeing a few of the other answers, I was curious if there was any performance differences between them. So I set up, what I think might be a reasonable test using an Array of 1,000,000 random string tuples and each implementation is run 100 times:
import scala.util.Random
object Demo extends App {
//Utility Code
def randomTuple(): (String, String) = {
val random = new Random
(random.nextString(5), random.nextString(5))
}
def timer[R](code: => R)(implicit runs: Int): Unit = {
var total = 0L
(1 to runs).foreach { i =>
val t0 = System.currentTimeMillis()
code
val t1 = System.currentTimeMillis()
total += (t1 - t0)
}
println(s"Time to perform code block ${total / runs}ms\n")
}
//Setup
case class Person(name: String, status: String) {
def verboseStatus() = s"$name is $status"
}
object PersonInfoU {
def unapply(x: (String, String)) = Some(Person(x._1, x._2))
}
val infos = Array.fill[(String, String)](1000000)(randomTuple)
//Timer
implicit val runs: Int = 100
println("Using two map operations")
timer {
infos.map(Person.tupled).map(_.verboseStatus)
}
println("Pattern matching and calling tupled")
timer {
infos.map {
case p # (_: String, _: String) => Person.tupled(p).verboseStatus()
}
}
println("Another pattern matching without tupled")
timer {
infos.map {
case (name, status) => Person(name, status).verboseStatus()
}
}
println("Using unapply in a companion object that takes a tuple parameter")
timer {
infos.map { case PersonInfoU(p) => p.name + " is " + p.status }
}
}
/*Results
Using two map operations
Time to perform code block 208ms
Pattern matching and calling tupled
Time to perform code block 130ms
Another pattern matching without tupled
Time to perform code block 130ms
WINNER
Using unapply in a companion object that takes a tuple parameter
Time to perform code block 69ms
*/
Assuming my test is sound, it seems the unapply in a companion-ish object was ~2x faster than the pattern matching, and pattern matching another ~1.5x faster than two maps. Each implementation probably has its use cases/limitations.
I'd appreciate if anyone sees anything glaringly dumb in my testing strategy to let me know about it (and sorry about that var). Thanks!
The extractor for a case class takes an instance of the case class and returns a tuple of its fields. You can write an extractor which does the opposite:
object PersonInfoU {
def unapply(x: (String, String)) = Some(PersonInfo(x._1, x._2))
}
infos.map { case PersonInfoU(p) => p.person + " is " + p.status }
You can use tuppled for case class
val infos = Array(("Matt", "Awesome"), ("Matt's Brother", "Just OK"))
infos.map(PersonInfo.tupled)
scala> infos: Array[(String, String)] = Array((Matt,Awesome), (Matt's Brother,Just OK))
scala> res1: Array[PersonInfo] = Array(PersonInfo(Matt,Awesome), PersonInfo(Matt's Brother,Just OK))
and then you can use PersonInfo how you need
You mean like this (scala 2.11.8):
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class PersonInfo(p: String)
Seq(PersonInfo("foo")) map {
case p# PersonInfo(info) => s"info=$info / ${p.p}"
}
// Exiting paste mode, now interpreting.
defined class PersonInfo
res4: Seq[String] = List(info=foo / foo)
Methods won't be possible by the way.
Several answers can be combined to produce a final, unified approach:
val infos = Array(("Matt", "Awesome"), ("Matt's Brother", "Just OK"))
object Person{
case class Info(name: String, status: String){
def verboseStatus() = name + " is " + status
}
def unapply(x: (String, String)) = Some(Info(x._1, x._2))
}
infos.map{ case Person(p) => p.verboseStatus }
Of course in this small case it's overkill, but for more complex use cases this is the basic skeleton.
i'm writing a play 2.3 application using secure social and reactivemongo library, with scala.
Now i'm trying to implement the UserService[T] trait but i'm getting compile errors on the updatePasswordInfo method.
This is the method:
def updatePasswordInfo(user: LoginUser,info: PasswordInfo): scala.concurrent.Future[Option[BasicProfile]] = {
implicit val passwordInfoFormat = Json.format[PasswordInfo]
//the document query
val query = Json.obj("providerId" -> user.providerId,
"userId" -> user.userId
)
//search if the user exists
val futureUser: Future[Option[LoginUser]] = UserServiceLogin.find(query).one
futureUser map {
case Some(x) => val newPassword = Json.obj("passswordInfo" -> info)// the new password
UserServiceLogin.update(query, newPassword) //update the document
val newDocument: Future[Option[LoginUser]] = UserServiceLogin.find(query).one
newDocument map {
case Some(x) => x
case None => None
} //return the new LoginUser
case None => None
}
}
And this is the compiler error:
/Users/alberto/git/recommendation-system/app/security/UserService.scala:203: type mismatch;
[error] found : scala.concurrent.Future[Product with Serializable]
[error] required: Option[securesocial.core.BasicProfile]
[error] newDocument map {
What's wrong?
If you map over a Future[A] you'll end up with a Future[B], where T is the type returned from the lambda you pass to map.
Since that lambda is returning a Future[B] in this case you end up with a Future[Future[B]], which doesn't match the expected type.
The easy fix is to use a flatMap, which takes a lambda going from A to Future[B].
Also, you're returning an Option[LoginUser] but the method is expected to return an Option[BasicProfile]. The compiler inferred a common supertype, which in this case is Product with Serializable, since they're both case classes.
To sum it up
scala.concurrent.Future[Product with Serializable]
^_____________________^^_________________________^
1 2
use flatMap instead of map
return a BasicProfile instead of LoginUser, or change the method return type to Future[Option[LoginUser]]
By the way, there's a lot of room for improvement, as you could use a for-comprehension and the OptionT monad transformer from scalaz to make the whole thing prettier.
Here's an example
import scalaz._; import Scalaz._
val newPassword = Json.obj("passswordInfo" -> info)
(for {
// this is done only for failing fast in case the user doesn't exist
_ <- optionT(UserServiceLogin.find(query).one)
_ <- optionT(Future.successful(Some(UserServiceLogin.update(query, newPassword))))
updatedUser <- optionT(UserServiceLogin.find(query).one)
} yield updatedUser).run
By the way, this works under the assumption that update is a sync call, which might (and I hope) not be the case. If it returns a Future[T] just change the code to
_ <- optionT(UserServiceLogin.update(query, newPassword).map(Some(_)))
or if it already returns a Future[Option[T]]
_ <- optionT(UserServiceLogin.update(query, newPassword))
If you really want to do the find to fail fast (though it is not so useful) and then reload the updated user from the database, something like this should do without the need for using scalaz :
def updatePasswordInfo(user: LoginUser,info: PasswordInfo): scala.concurrent.Future[Option[BasicProfile]] = {
implicit val passwordInfoFormat = Json.format[PasswordInfo]
//the document query
val query = Json.obj("providerId" -> user.providerId,
"userId" -> user.userId)
val newPassword = Json.obj("passswordInfo" -> info)
//update the document
for {
userO <- UserServiceLogin.find(query).one[BasicProfile] //fail fast (not sure this is really useful)
updatedUser<-UserServiceLogin.update(query, newPassword).map(_=>userO).recover{case _ =>None}
actualUser <- UserServiceLogin.find(query).one[BasicProfile]
} yield actualUser
}
There are several ways in which your code can be improved.
For example, you don't need to find the user before firing the query.
Also, it would be good to check if your query actually succeeded (if the API allows it).
Third, I am not sure in which way LoginUser corresponds to the BasicProfile. Your code doesn't seem to do any kind of conversion. If LoginUser is a subclass of BasicProfile, or can be cast to BasicProfile somehow, you can try something like this:
def updatePasswordInfo(user: LoginUser,info: PasswordInfo): scala.concurrent.Future[Option[BasicProfile]] = {
implicit val passwordInfoFormat = Json.format[PasswordInfo]
//the document query
val query = Json.obj("providerId" -> user.providerId,
"userId" -> user.userId
)
UserServiceLogin.update(query, newPassword) //update the document
for {
user <- UserServiceLogin.find(query).one
} yield user.map(_.asInstanceOf[BasicProfile]) //return the new LoginUser
}
I have a Scala case class containing command-line configuration information:
case class Config(emailAddress: Option[String],
firstName: Option[String]
lastName: Option[String]
password: Option[String])
I am writing a validation function that checks that each of the values is a Some:
def validateConfig(config: Config): Try[Config] = {
if (config.emailAddress.isEmpty) {
Failure(new IllegalArgumentException("Email Address")
} else if (config.firstName.isEmpty) {
Failure(new IllegalArgumentException("First Name")
} else if (config.lastName.isEmpty) {
Failure(new IllegalArgumentException("Last Name")
} else if (config.password.isEmpty) {
Failure(new IllegalArgumentException("Password")
} else {
Success(config)
}
}
but if I understand monads from Haskell, it seems that I should be able to chain the validations together (pseudo syntax):
def validateConfig(config: Config): Try[Config] = {
config.emailAddress.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Email Address")) >>
config.firstName.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("First Name")) >>
config.lastName.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Last Name")) >>
config.password.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Password"))
}
If any of the config.XXX expressions returns Failure, the whole thing (validateConfig) should fail, otherwise Success(config) should be returned.
Is there some way to do this with Try, or maybe some other class?
It's pretty straightforward to convert each Option to an instance of the right projection of Either:
def validateConfig(config: Config): Either[String, Config] = for {
_ <- config.emailAddress.toRight("Email Address").right
_ <- config.firstName.toRight("First Name").right
_ <- config.lastName.toRight("Last Name").right
_ <- config.password.toRight("Password").right
} yield config
Either isn't a monad in the standard library's terms, but its right projection is, and will provide the behavior you want in the case of failure.
If you'd prefer to end up with a Try, you could just convert the resulting Either:
import scala.util._
val validate: Config => Try[Config] = (validateConfig _) andThen (
_.fold(msg => Failure(new IllegalArgumentException(msg)), Success(_))
)
I wish that the standard library provided a nicer way to make this conversion, but it doesn't.
It's a case class, so why aren't you doing this with pattern matching?
def validateConfig(config: Config): Try[Config] = config match {
case Config(None, _, _, _) => Failure(new IllegalArgumentException("Email Address")
case Config(_, None, _, _) => Failure(new IllegalArgumentException("First Name")
case Config(_, _, None, _) => Failure(new IllegalArgumentException("Last Name")
case Config(_, _, _, None) => Failure(new IllegalArgumentException("Password")
case _ => Success(config)
}
In your simple example, my priority would be to forget monads and chaining, just get rid of that nasty if...else smell.
However, while a case class works perfectly well for a short list, for a large number of configuration options, this becomes tedious and the risk of error increases. In this case, I would consider something like this:
Add a method that returns a key->value map of the configuration options, using the option names as the keys.
Have the Validate method check if any value in the map is None
If no such value, return success.
If at least one value matches, return that value name with the error.
So assuming that somewhere is defined
type OptionMap = scala.collection.immutable.Map[String, Option[Any]]
and the Config class has a method like this:
def optionMap: OptionMap = ...
then I would write Config.validate like this:
def validate: Either[List[String], OptionMap] = {
val badOptions = optionMap collect { case (s, None) => s }
if (badOptions.size > 0)
Left(badOptions)
else
Right(optionMap)
}
So now Config.validate returns either a Left containing the name of all the bad options or a Right containing the full map of options and their values. Frankly, it probably doesn't matter what you put in the Right.
Now, anything that wants to validate a Config just calls Config.validate and examines the result. If it's a Left, it can throw an IllegalArgumentException containing one or more of the names of bad options. If it's a Right, it can do whatever it wanted to do, knowing the Config is valid.
So we could rewrite your validateConfig function as
def validateConfig(config: Config): Try[Config] = config.validate match {
case Left(l) => Failure(new IllegalArgumentException(l.toString))
case _ => Success(config)
}
Can you see how much more functional and OO this is getting?
No imperative chain of if...else
The Config object validates itself
The consequences of a Config object being invalid are left to the larger program.
I think a real example would be more complex yet, though. You are validating options by saying "Does it contain Option[String] or None?" but not checking the validity of the string itself. Really, I think your Config class should contain a map of options where the name maps to the value and to an anonymous function that validates the string. I could describe how to extend the above logic to work with that model, but I think I'll leave that as an exercise for you. I will give you a hint: you might want to return not just the list of failed options, but also the reason for failure in each case.
Oh, by the way... I hope none of the above implies that I think you should actually store the options and their values as an optionMap inside the object. I think it's useful to be able to retrieve them like that, but I wouldn't ever encourage such exposure of the actual internal representation ;)
Here's a solution that I came up with after some searching and scaladocs reading:
def validateConfig(config: Config): Try[Config] = {
for {
_ <- Try(config.emailAddress.
getOrElse(throw new IllegalArgumentException("Email address missing")))
_ <- Try(config.firstName.
getOrElse(throw new IllegalArgumentException("First name missing")))
_ <- Try(config.lastName.
getOrElse(throw new IllegalArgumentException("Last name missing")))
_ <- Try(config.password.
getOrElse(throw new IllegalArgumentException("Password missing")))
} yield config
}
Similar to Travis Brown's answer.
I have a pattern to process web service requests using chained partial functions (this is a chain of responsibility pattern, I think?). In my example, let's say there are two parameters for the request, a string Id and a date. There's a verification step involving the id, a verification step checking the date, and finally some business logic that use both. So I have them implemented like so:
object Controller {
val OK = 200
val BAD_REQUEST = 400
type ResponseGenerator = PartialFunction[(String, DateTime), (String, Int)]
val errorIfInvalidId:ResponseGenerator = {
case (id, _) if (id == "invalid") => ("Error, Invalid ID!", BAD_REQUEST)
}
val errorIfFutureDate:ResponseGenerator = {
case (_, date) if (date.isAfter(DateTime.now)) => ("Error, date in future!", BAD_REQUEST)
}
val businessLogic:ResponseGenerator = {
case (id, date) => {
// ... do stuff
("Success!", OK)
}
}
def handleRequest(id:String, date:DateTime) = {
val chained = errorIfInvalidId orElse errorIfFutureDate orElse businessLogic
val result: (String, Int) = chained(id, date)
// make some sort of a response out of the message and status code
// e.g. in the Play framework...
Status(result._2)(result._1)
}
}
I like this pattern because it's very expressive - you can easily grasp what the controller method logic is just by looking at the chained functions. And, I can easily mix and match different verification steps for different requests.
The problem is that as I try to expand this pattern it starts to break down. Suppose my next controller takes an id I want to validate, but does not have the date parameter, and maybe it has some new parameter of a third type that does need validation. I don't want to keep expanding that tuple to (String, DateTime, Other) and have to pass in a dummy DateTime or Other. I want to have partial functions that accept different types of arguments (they can still return the same type). But I can't figure out how to compose them.
For a concrete question - suppose the example validator methods are changed to look like this:
val errorIfInvalidId:PartialFunction[String, (String, Int)] = {
case id if (id == "invalid") => ("Error, Invalid ID!", BAD_REQUEST)
}
val errorIfInvalidDate:PartialFunction[DateTime, (String, Int)] = {
case date if (date.isAfter(DateTime.now)) => ("Error, date in future!", BAD_REQUEST)
}
Can I still chain them together? It seems like I should be able to map the tuples to them, but I can't figure out how.
I'm a big fan of using scalaz's Validation for things like this. It gives you quite a bit of control over what you want to do with errors and how to handle them. Here's an example using you're controller:
import scalaz._
import Scalaz._
object Controller {
val OK = 200
val BAD_REQUEST = 400
case class Response(response: String, status: Int)
def validateIfInvalidId(id: String) = (id == "invalid") ?
Response("Error, Invalid ID!", BAD_REQUEST).fail[String] |
id.success[Response]
def validateIfFutureDate(date: DateTime, currentDate: DateTime = DateTime.now) = (date.isAfter(currentDate)) ?
Response("Error, date in future!", BAD_REQUEST).fail[DateTime] |
date.success[Response]
def handleRequest(id: String, date: DateTime) = {
val response = for {
validatedId <- validateIfInvalidId(id)
validatedDate <- validateIfFutureDate(date)
} yield {
// ... do stuff
Response("Success!", OK)
}
// make some sort of a response out of the message and status code
// e.g. in the Play framework...
response.fold(
failure => Status(failure.response, failure.status),
success => Status(success.response, success.status)
)
}
}
You can move the different validation functions off into their own world and then compose them anytime you want with the for comprehension in scala.
Okay, I found a way to do this which seems not too bad. Originally I was thinking it might work to wrap the "base" version of the partial function in another partial function that takes the tuple. But I couldn't figure out how to do it, until I hit on the obvious-in-retrospect idea of using isDefined in a case guard statement. Like so:
// "base" version
val errorIfInvalidId:PartialFunction[String, (String, Int)] = {
case id if (id == "invalid") => ("Error, Invalid ID!", BAD_REQUEST)
}
// wrapped to take tuple as parameter
val wrappedErrorIfInvalidId:PartialFunction[(String, DateTime), (String, Int)] = {
case (id, _) if (errorIfInvalidId.isDefinedAt(id)) => errorIfInvalidId(id)
}
This approach is serviceable, though I still wonder if there isn't a more direct way of accomplishing it. (I also may switch over to the Scalaz validation suggested by Noah after I get a chance to play with it a bit.)
You can make PartialFunction more generic, making it PartialFunction[Any, (String, Int)]
Altho, mb it will be slower. Do not know matching mechanics under PartialFunction