So, I am totally new to Scala, coming from a Java background and have been given a huge scala code base to learn. And, I am very lost and would appreciate any help.
I have the below function that I want to re-arrange. Currently, the function calls two functions in a row and then returns the result. The first function returns a boolean and the second function returns a User. However, what actually should happen is that the second function should only be called if the first function returns true. So, I need to rearrange it to check the return value of the first function before continuing. Every time I rewrite it to do that, I either get a compile error or exception. It is supposed to return a Future[Option[User]] and the first function doesn't return a User. I just want to return None if FunctionA fails, but because it expects Future[Option[X]]], it is unhappy. So, below is the function:
private def profileForCredentials(userId: String, password: String)(implicit ec: ExecutionContext): Future[Option[User]] =
{
val credentials: Throwable \/ Boolean = {
try {
FunctionA(userId, password).right[Throwable]
}
catch {
case npe: NullPointerException =>
npe.left[Boolean]
}
}
//This function doesn't need to be called unless credentials=true
FunctionB(id, userId).map {
case maybeUser#Some(user) =>
credentials match {
case \/-(x) if x =>
user.some
case _ =>
None
}
case None =>
None
}
}
You guys just got carried away with the scalaz.
I am going to bookmark this page to show people at work as an illustration why we should not be using all this fancy stuff.
Just do this:
Try {
FunctionA(userId, password)
}
.toOption
.collect { case(true) =>
FunctionB(id, userId)
}
.getOrElse(Future.value(None))
Related
No need to pay attention to the purpose of the function here, it's only for demonstration:
def readAllByPersonOrFail(person: Person, otherPersonId: Long): Future[List[Person]] = {
val personSiblingsFuture: Future[List[Person]] = personSiblingsDomain.readAllByPersonId(person.id)
personSiblingsFuture.map { persons =>
persons.find(_.id == otherPersonId) match {
case Some(person) =>
person.isActive match {
case true => person
case false => throw new IllegalArgumentException("something inactive")
}
case None => throw new IllegalArgumentException("something wrong ehre")
}
}
personSiblingsFuture
}
I would like to return personSiblingsFuture above iff it validates (makes sure correct person is in the list and is active), otherwise throw the exception. I don't think the above code is doing the right thing as it is not existing upon failure.
Take a look at scala.concurrent.Future.map. This creates a new future, whose value is resolved by applying a function to the successful result of this future.
Note that here you're throwing away the resulting future you just created with .map() too.
There are a few areas to solve your problem, though you should question more deeply the use of exceptions with Futures. Scala provides concepts like Future, Option, and Try specifically to avoid throwing exceptions and have a clearer control flow.
Option 1, return the mapped future
In your funciton,
def func(...): Future[List[Person]] {
val personSiblingsFuture = ...;
personSiblingsFuture.map { persons =>
...
}
}
// note we're not returning personSiblingsFuture,
// but the mapped result
When someone actually tries to get the value of the future, e.g. by using .value, they might see an exception intead:
def main() {
val future = func(...); // this is fine
val my_list = future.value; // awaits Future, might throw here
}
Option 2, actually await the list and throw in the function
Returning a future that might throw is strange, it might be a bit easier if the you actually explicitly a had a function that might throw, e.g.
/** jsdoc describing function **/
def funcMightThrow(...): List[Person] {
val personSiblingsFuture = ...;
val personSiblings = personSiblingsFuture.value;
personSiblings.find(_.id == otherPersonId) match {
case Some(person) =>
person.isActive match {
case true => personSiblings
case false => throw new IllegalArgumentException("something inactive")
}
case None => throw new IllegalArgumentException("something wrong ehre")
}
}
Option 3, consider making return types more explicit
def func(...): Future[Try[List[Person]]] {
val personSiblingsFuture = ...;
personSiblingsFuture.map { persons =>
...
// successful case returns 'persons' (List[Person])
// fail cases return Failure(...) instead
}
} // return the mapped future
You can also return Try[List[Person]] rather than a Future[] of that, by using .value, which makes func a blocking function.
The following block of code fails to build with error :
value flatMap is not a member of Product with Serializable
[error] if (matchingUser.isDefined) {
Here's the code:
for {
matchingUser <- userDao.findOneByEmail(email)
user <- {
if (matchingUser.isDefined) {
matchingUser.map(u => {
// update u with new values...
userDao.save(u)
u
})
} else {
val newUser = new User(email)
userDao.create(newUser)
newUser
}
}
} yield user
Method userDao.findOneByEmail(email) returns anFuture[Option[User]]object.
My Google searches are only aboutEitherwithRightandLeft` types.
Maybe I'm not doing this the proper way, please teach me how to properly do this.
The first branch of the if statement returns Option[User], the other one returns User. So, the result of the entire statement is inferred to have type Product with Serializable because it is the only common supertype of the two.
You could wrap the last statement inside the if into an Option (just do Option(newUser) instead of newUser) or, better yet, use fold instead of the whole if(matchingUser.isDefined) {...} thingy:
matchingUser.fold {
val u = new User(email)
userDao.create(u)
u
} { u =>
userDao.save(u)
u
}
This will make the result of that statement to be Option[User] as you probably intended ... but it still will not compile.
The problem is that you cannot mix different types of monads in the for-comprehension: since the first one was Future, all the others have to be as well. You can't have an Option there.
How to get around that? Well, one possibility is to make userDao.create and userDao.save return a future of the object they just saved. That is, probably a better thing to do in general, then what you have, because now you are returning the user before it was actually stored ... What if the create operation fails afterwards? Then you can just rewrite your for-comprehension like this:
for {
matchingUser <- userDao.findOneByEmail(email)
user <- matchingUser.fold(userDao.create(new User(email)))(userDao.save)
} yield user
Or just get rid of it entirely (for-comprehension is an overkill for simple cases like this):
userDao
.findOneByEmail(email)
.flatMap(_.fold(usrDao.create(new User(email)))(userDao.save))
Or, it may look a little nicer with pattern matching instead of fold in this case:
userDao
.findOneByEmail(email)
.flatMap {
case Some(u) => userDao.save(u)
case None => userDao.create(new User(email))
}
Here is my test example to reproduce your issue with solution.
Basically your user returns wrapper around Future (Option of Future), but it expected to be Future, as the first statement in for-comprehension.
That is why I've applied some addition unwrapping. See sample below.
Note: it does not looks so nice, I'd prefer to rewrite it with flatMap map.
object T {
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def future1: Future[Option[Int]] = ???
def future2(i: Int): Future[Double] = ???
for {
matchingUser <- future1
user <- {
if (matchingUser.isDefined) {
matchingUser.map { i =>
future2(i)
}
} else {
Some(future2(42))
}
} match {
case None => Future.successful(-42.0)
case Some(x) => x
}
} yield user
}
And the same implemented with flatMap:
val userFuture = future1.flatMap {
case Some(i) => future2(i)
case None => future2(42)
}
I am new to Play Framework using Scala. I want to evaluate a condition and in that condition evaluates to true, I want to send a response and exit at that point. However, the code below that I am trying continues till the end.
I tried breaking with a return statement - However, I get a type mismatch. Can someone help me out with this?
def hello = Action { request =>
if (true) {
Ok("in If")
// Return at this point
}
print("This line should not be printed")
Ok("final")
}
EDIT
Assume a GET call is being made with 4 parameters - name, age, married, spouse. I want to make sure all 3 params (name, age, married) are passed in, and if married is true, check if spouse is passed in. If this validation fails, I want to respond saying Bad Request. Else, continue with logic. How do I write this?
Here is an alternative way to do it:
case class QueryInput(name: String, age: Int, married: Boolean, spouse: Option[String]) {
def validated = if(married && spouse.isEmpty) None else Some(this)
}
def validateInput(request: RequestHeader) = {
val input = for {
name <- request.queryString.get("name").flatMap(_.headOption)
age <- request.queryString.get("age").flatMap(_.headOption.flatMap(a=>Try(a.toInt).toOption))
married <- request.queryString.get("married").flatMap(_.headOption.map(_=="true"))
} yield {
QueryInput(name, age, married, request.queryString.get("spouse").flatMap(_.headOption))
}
input.flatMap(_.validated)
}
def hello() = Action { request =>
validateInput(request) match {
case Some(input) => Ok(input.toString())
case None => BadRequest
}
}
In fact, there are many options. You could also play with the Either class to do validation: Left value to accumulate errors and return bad request, right value to construct your validated input.
My recommendation would be to have a method for validating the parameters. Then do a simple if/else to check if the parameters are valid and return a success or a general error.
If you really want a specific
First thing:
When the block evaluates, all of its expressions and declarations are processed in order, and then the block returns the value of the last expression as its own value.
Second: don't use return.
And the third one is a Play Framework way of resolving your problem: action composition. Though I would not say that it is trivial.
You can do this, by putting a return Ok in but really, thats not the scala way. What you want to do is to change your mindset and imagine everything as a function. If you didnt know, if-then-else always returns a value. For example, you can actually write if this way:
def hello = Action { request =>
val result = if (true) {
Ok("foo")
} else {
Ok("bar")
}
result
}
of course, an even more scala way is to use matchers
def hello = Action { request =>
val result = true match {
case true => Ok("foo")
case _ => Ok("bar")
}
result
}
Take that one step further and you dont even need to specify the result object at all, because scala figures out the returning object based on the last object returned/created.
def hello = Action { request =>
true match {
case true => Ok("foo")
case _ => Ok("bar")
}
}
EDIT: TO answer the OP's edit, you still want to use the matcher. Assuming your vals are options, heres what you do:
def hello(nameOpt:Option[String], ageOpt:Option[String], marriedOpt:Option[String]) = Action { request =>
(nameOpt, ageOpt, marriedOpt) match {
case (Some(name), Some(age), Some(married)) => Ok("all 3 are given")
case (Some(name), Some(age), _) => Ok("all 2 are given")
// functionally same as above
// case (Some(name), Some(age), None) => Ok("all 2 are given")
// some combination of the above
case (None, None, Some(married)) => Ok("married but no name or age")
// default case
case _ => Ok("bar")
}
}
I'd like to keep my application as asynchronously as possible. Now I have this repository:
object LanguageRepository extends LanguageRepositoryTrait
{
private val languages = TableQuery[Languages]
private def db:Database = Database.forDataSource(DB.getDataSource())
private def filterQuery(id: Long): Query[Languages, Language, Seq] = languages.filter(_.id === id)
private def filterCode(code: String): Query[Languages, Language, Seq] = languages.filter(_.code === code)
private def all() : Query[Languages, Language, Seq] = languages
override def find(id: Long): Future[Language] =
{
try db.run(filterQuery(id).result.head)
finally db.close()
}
override def find(code: String): Future[Language] =
{
try db.run(filterCode(code).result.head)
finally db.close()
}
override def get(): Future[Seq[Language]] =
{
try db.run(all().result)
finally db.close()
}
}
When I call a url like "domain.tld/{language}" I want to check whether the given language(code) actually exists. Like, if the site isn't available in french (fr) I want to throw an exception or a 404.
Now, my problem is that this whole asynchronously thing is pretty cool and while I do think to understand the theory behind it, I'm rather baffled right now. I mean, I want this to be non-blocking (and asynchronously, which is the reason for me using Future and async ;))
In my controller I want to do something like:
def checkLanguage(language:String) = Action
{
val lang:Future[Language] = languageRepository.find(language)
lang.onComplete
{
case Success(s) = Ok("Yay")
case Failure(f) = 404("Oh no!")
}
}
Of course this can't work, but that's a schema of how I want to have things working. I want to wait or postpone the rendering of the site, until it's confirmed that the given language-code is valid or invalid.
I had a look at the Playframeworks async-documentation for 2.3.6 (https://www.playframework.com/documentation/2.3.6/ScalaAsync) but I couldn't really get this to work as intended.
Any input appreciated!
From your db query don't use .head instead use .headOption. that way ur return type will be a Future [Option [x]]
In ur controller u can do something like this
Lang.map { case Some (x) => Ok (x)
case None => 404 ( "not found ")
}
Try this,
Action.async {
val lang:Future[Option[Language]] = languageRepository.find(language)
lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
}
First of all, I am assuming that if there is a possibility that a language will not exist then languageRepository.find(language) should return an Option of Language. Change Future[Language] to Future[Result] and use Action.async instead of Action
Now for some explanation, Action takes a block whose result should be Result. However, what you get is Future[Option[Language]]. Play provides async method for Action which needs Future[Result] and it takes cares of completing the request.
So, you need to convert Future[Option[Language]] to Future[Result].
lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
We map over the lang, if the Option[Language] is not None then we convert it to Ok("yay") else we convert it to NotFound
Even, If you don't get Option[Language], the idea remains the same. Convert Future[Language] to Future[Result] and use Action.async instead of Action
I know that this is not the Scala way of writing things. I think, in Scala you would use map. But I would like to write it this way, because it is more Java/c++ like.
However writing the following code the Scala compiler complains "method addGroup has return statement; needs result type".
Omitting the return and using an else branch works. But for formating reasons I'd like to use a return, because I don't want to indent the rest of the code which would happen if you use "else {}".
Where to add the result type. And is "Future[Result]" the correct type?
def addGroup = Action { implicit request =>
val optionUser = GetUserFromSession(request)
if (optionUser == None) {
return Redirect(routes.ApplicationUser.show(0))
}
Redirect(routes.ApplicationUser.show(optionUser.get.id))
}
You can't. The body of Action.apply is an anonymous function that you're trying to prematurely return from. The problem is, the return keyword in Scala returns from the inner-most named method, which this most certainly is not. So you'll be trying to return a Result where the method requires a Action[A].
The only way this can work is if you split the functions:
def addGroup = Action { implicit request =>
result(request)
}
// Could have a better name, but whatever, you shouldn't do this.
def result(request: Request): Result = {
val optionUser = GetUserFromSession(request)
if (optionUser == None) {
return Redirect(routes.ApplicationUser.show(0))
}
Redirect(routes.ApplicationUser.show(optionUser.get.id))
}
Using return makes code weird and difficult to read, so please don't.
If saving a single indentation is really a concern, what about this?
def addGroup = Action { implicit request =>
val optionUser = GetUserFromSession(request)
if (optionUser == None) Redirect(routes.ApplicationUser.show(0))
else Redirect(routes.ApplicationUser.show(optionUser.get.id))
}
Personally, I would re-write this using map and getOrElse:
def addGroup = Action { implicit request =>
GetUserFromSession(request) map { user =>
Redirect(routes.ApplicationUser.show(user.id))
} getOrElse {
Redirect(routes.ApplicationUser.show(0))
}
}
It removes the need to use .get and also prioritizes the positive branch.