for comprehensions with if guard - scala

How do I use for comprehensions with if guard?
type Error = String
type Success = String
def csrfValidation(session:Session, body:JsValue):Either[Error,Success] = {
val csrfRet = for (csrfSession <- csrfStateSessionValidation(session).right;
csrfReq <- csrfStateReqBodyValidation(body).right if (csrfSession == csrfReq)) yield (csrfReq)
if (csrfRet.isRight)
Right(csrfRet)
else {
Logger.warn("request and session csrf is not the same")
Left("Oops,something went wrong, request and session csrf is not the same")
}
}
I got this error when using it.
'withFilter' method does not yet exist on scala.util.Either.RightProjection[Error,Success], using `filter' method instead
EDIT:
I got another error. I think it returns an option result when if guard is used.
[error] type mismatch;
[error] found : Option[scala.util.Either[Nothing,controllers.ProfileApiV1.Success]]
[error] required: scala.util.Either[?,?]
[error] csrfReq <- csrfStateReqBodyValidation(body).right if (csrfSession == csrfReq)) yield (csrfReq)
EDIT2
This is what I did to fix above error. I also move if-guard to later process.
val result = for {
foo <- Right[String,String]("teststring").right
bar <- Right[String,String]("teststring").right
} yield (foo, bar)
result fold (
ex => Left("Operation failed with " + ex),
v => v match {
case (x,y) =>
if (x == y) Right(x)
else Left("value is different")
}
)

I believe what you are seeing is a compiler warning and not an actual error. The RightProjection does not support withFilter which is what is "preferred" (but not yet required) for a guard condition, so plain old filter is used instead. As to the difference to these functions and why this came about, check out the link below for an explanation.
http://scala-programming-language.1934581.n4.nabble.com/Rethinking-filter-td2009215.html#a2009218

Add either a semi-colon or a new line just before the if.

Related

Type mismatch even when Vector type has been declared

I have a very simple method in a class:
def partysCandidate(party: String): Vector[Candidate]= {
var result = Vector[Candidate]()
for (candidate <- this.candidates) {
if (candidate.party == party) result = result + candidate
}
result
}
However it gave me Error type mismatch found : package.Candidate required: String at result + candidate. I couldn't figure out why. Any help would be much appreciated.
Many thanks!
There is no method + on a Vector, there are +: (prepend), :+ (append) (colon is treated as mnemonic for collection), etc.
There is however any2stringadd implicit class which - when you call sth.+(x: String) on something which doesn't have such method - call .toString on sth before appending x to it, which would return String. This results in the error you see. Accidental usage of this extension method is a reason why this got deprecated and why many linters defend against it.
Your code could be fixed by using the right operator e.g.
if (candidate.party == party) result = result :+ candidate
however in this particular case you can just use for-comprenension to build the result without mutation
def partysCandidate(party: String): Vector[Candidate] =
for {
candidate <- candidates
if candidate.party == party
} yield candidate
or even shorter
def partysCandidate(party: String): Vector[Candidate] =
candidates.filter(c => c.party == party)

Issues returning a value in Scala inside an if statement

I've got this 'if' condition inside a recursion function :
if (tmpList.size == 14) {
val FBData = Entry (tmpList(0), tmpList(1),tmpList(2),tmpList(3),tmpList(4),tmpList(5).toInt,tmpList(6).toInt,tmpList(7).toInt,tmpList(8).toInt,tmpList(9).toInt,tmpList(10).toInt,tmpList(11).toInt,tmpList(12).toInt,tmpList(13).toInt)
if (index == lines.size - 1) {
List(FBData)
} else {
val Data = pRecurrsioon(lines, index + 1) ++ FBData.toList
}
}
When I runt this through a Scala compiler I get this issue:
31: error: type mismatch;
found : Unit
required: List[HelloWorld.Entry]
}
I don't know why this keeps happening or how to fix it. Apparently im returning an Unsigned integer at some point but I can't see where.
In Scala, the body of the if and the else do return values. The following is also valid (and still has your bug):
val ifResult = if (index == lines.size - 1) {
//this works, and List(FBData) will be assigned to ifResult
List(FBData)
} else {
//this returns Unit as a result of the assignment operation
val Data = pRecurrsioon(lines, index + 1) ++ FBData.toList
}
The compiler tries to assign to ifResult either the body of the if or the else. For this to work, it has to unify the types. This causes the error message you see, while checking the body of the else and trying to get the same type of it as from the if-body:
31: error: type mismatch; found : Unit required: List[HelloWorld.Entry] }

Why Scala return in for-loop give Unit value type?

I have written a for loop to traverse Map, I want this function return key immediately when found some value (both of key and value is Int type)
var hs:Map[Int,Int] = Map(1 -> 1, 2 -> 2)
for ((k,v) <- hs) {
if (v == 1)
return k
}
but, scala give me the error message:
error: type mismatch;
found : Unit
required: Int
for ((k,v) <- hst)
^
one error found
then I change to
var result = 0
for ((k, v) <- hst){
if (v == 1)
result = k
}
result
then, it works well. Why the first version has type issues?
The compile error is explained by #D.Peter, It's lack of a return for this clause.
In Scala, you can use find to do that, like:
hs.find(_._2 == 1).map(_._1).getOrElse(0) // get or return default value.
You forgot to return something if you function never enters in the if statement
def a() : Int = {
var hs:Map[Int,Int] = Map(1 -> 1, 2 -> 2)
for ((k,v) <- hs) {
if (v == 1){
return k
}
}
return -1
}
The accepted answer is not very accurate because it's not about entering if statement, even if you remove if condition it will still not compile.
The problem is the for loop itself. Without yield it simply acts as a construct for side effects. Meaning it returns Unit. Pretty much like foreach semantics.
Read more here.

scala sys.process_ illegal start of simple expression error

I got an error "illegal start of simple expression" in scala while trying to do this:
def test() = {
val h = "ls"!
if (h != 0)
println("error")
}
this is the error
[error] if (h != 0)
[error] one error found
[error] (compile:compileIncremental) Compilation failed
Can anyone tell me what I did wrong?
Scala compiler is getting confused here because you are calling ! as a postfix operator. It can't figure out which version to use and where to place the implied semicolon. You can either add a semicolon like this:
def test() = {
val h = "ls"!;
if (h != 0)
println("error")
}
or call it as a method:
def test() = {
val h = "ls".!
if (h != 0)
println("error")
}
or add a new line:
def test() = {
val h = "ls"!
if (h != 0)
println("error")
}
Best practice to use a postfix operator is to use dot . operator. You should invoke it like val h = "ls".!
It makes code less ambiguous as semicolon is optional in Scala and compiler might treat it as an infix notation.
From Scala doc:
This style is unsafe, and should not be used. Since semicolons are
optional, the compiler will attempt to treat it as an infix method if
it can, potentially taking a term from the next line.
For full reference see this link: Suffix Notation. This post may also be helpful Scala's "postfix ops".

Reading input throws compile error

Pretty new to scala. I have this function:
def retrieveValue(valueName:String) : Double = {
for (ln <- io.Source.stdin.getLines) {
val parseResult = parseValue(ln)
parseResult match {
case Right(x) => return x
case Left(error) => println(error.message + " Please try again.")
}
}
}
And I'm getting this compile error:
QuadSolver.scala:14: error: type mismatch;
found : Unit
required: Double
for (ln <- io.Source.stdin.getLines) {
What exactly am I doing wrong?
parseResult match {
case Right(x) => x //note that `return` keyword is not needed
case Left(error) => println(error.message + " Please try again.") //returns Unit
}
This piece of code return either a Double or a Unit (Unit provided by println), therefore compiler expecting a Double as method's return type obviously complains.
In functional programming, it's better to have each function strictly following Single-Responsibility Principle.
Thus, you should have one function aiming to retrieve the value and one to print the result.