Why doesn't the scala compiler generate a warning on if statements that always yield false inside a pattern match? - scala

The scala compiler should generate warnings for the if statements I've commented on below, but it doesn't. Why?
sealed trait T
object A extends T
val s:Seq[T] = Seq(A)
val result = s.map {
//This if should produce a compiler warning
case a if(a == "A") =>
"First"
case a =>
//This if should produce a compiler warning
if (a == "A") {
"Second"
}
else
{
"Third"
}
}
The result will be "Third" as you'd expect, but the compiler should have generated a warning on the case a if(a == "A") and on the if (a == "A"), but alas there is no warning.
If I write the following code it behaves like I would expect:
if(A == "A"){
println("can't happen")
}
// warning: comparing values of types A.type and String using `==' will always yield false
Why is this happening?
Edit: I'm using Scala 2.10.1.

Because it can happen. If I simply kept some internal state and returned different results for == "A" on the first and second call, then I can get "Second".
You've provided a definition of A that guarantees it can't happen, but that requires examination of the whole program, and compiler warnings are only local.

May you will have inherited class with overloaded == method with string argument…

Related

Scala unused expression error with if statement

I'm very new to Scala, and tried to write a simple Scala program that gets the maximum value. I found something weird (probably a language-specific feature). Here it is:
def max(xs: List[Int]): Int = {
if (xs.isEmpty) {
throw new java.util.NoSuchElementException
}
def maxAux(x: List[Int], curMax: Int): Int = {
if (x.isEmpty) {
curMax
}
if (x.head > curMax) {
maxAux(x.tail, x.head)
}
else {
maxAux(x.tail, curMax)
}
}
maxAux(xs.tail, xs.head)
}
}
For some reason, inside of maxAux function, the return of the first if statement gives me an IntelliJ warning that it is an "unused expression". Turns out it is correct because that line doesn't seem to return. To get around that issue, the second if statement in maxAux I changed to an else if, and then everything worked as intended. The other fix would be to add a return statement before curMax, but apparently using return is bad style/practice.
TL;DR: Can anyone explain why in the code above curMax doesn't return?
The immediate problem is that Scala returns the value of the last expression in a block which is the second if/else expression. So the value of the first if is just discarded. This can be fixed by making the second if an else if so that it is a single expression.
A better solution is to use match, which is the standard way of unpicking a List:
def maxAux(x: List[Int], curMax: Int): Int =
x match {
case Nil =>
curMax
case max :: tail if max > curMax =>
maxAux(tail, max)
case _ :: tail =>
maxAux(tail, curMax)
}
In def maxAux, the control-flow can enter the first if-branch, whose body yields curMax. But that if-statement is not the last statement in maxAux, another if- or else-branch will follow, and they determine the result.
If you test your function (note that your code currently doesn't compile!), e.g. via println(max(List(1,3,2,5,0))), then you'll get a NoSuchElementException, which is a consequence of your current (incorrect) implementation.
You have various options now, e.g. the following two, which only minimally change your code:
Fix the if-else cascade (which you could also rewrite into a pattern matching block):
if (x.isEmpty) {
curMax
} else if (x.head > curMax) {
maxAux(x.tail, x.head)
} else {
maxAux(x.tail, curMax)
}
Use a return statement (though you should be careful with the use of return in Scala. See the comments under this answer):
if (x.isEmpty) {
return curMax
}

How to recreate if else statements in Scala using objects?

I'm trying to implement my own if-else like control structures in Scala using thunk code. The point is to create a control structure with the same behavior as if-else statements but a custom name. The thing is that i cannot figure out how to implement the complete case of an if else statement, i get stuck implementing the if.
object Si {
def apply[U](expression:Boolean)(instruction:U):U = {
if (expression) instruction
}
}
This piece of code doesn't compile. It says that the value Any doesn't conform to expected type U. I know what the problem is, but i cannot figure out the way to implement the "else" part.
Could anyone please give me any idea of how they would implement it?
You usually create these kinds of DSL's by returning intermediate objects until the whole expression is complete.
object fi {
def apply[R](cond: Boolean)(then: => R): IfThen[R] = new IfThen(cond, then)
class IfThen[R](cond: Boolean, then: => R) {
def esle[S >: R](ethen: => S) = if (cond) then else ethen
}
}
You can then use it almost exactly like a normal if ... else .... Only the else part is always required.
scala> fi (1 > 2 - 3) { Some("foo") } esle { None }
res9: Option[String] = Some(foo)
That's because you don't have an else that also returns a U
you can return an Option[U] instead and return None in the else

Scala if-else condition not working on REPL

I am executing this on the Scala Interpreter - REPL, I am trying to set the value of the Tuple(account_df_index, disposition_df_index) to (0,1), but on execution an error is thrown on the first line of the else block. If my understanding is correct, (0,1) should be assigned and the else block must not execute. Where am I wrong?
val extra_params = None
val extra_params_map = if (extra_params.equals(None)) {None} else{
extra_params.toMap}
val (account_df_index, disposition_df_index) = if(extra_params.equals(None))
{
(0,1)
} else {
if(extra_params_map.contains("dataframe_index_map"){
val dataframe_map =
extra_params_map.get("dataframe_index_map")
.get.parseJson
.convertTo[Map[String, Int]]
val account_df_index = dataframe_map.getOrElse("account", 0)
val disposition_df_index = dataframe_map.getOrElse("disposition", 1)
(account_df_index, disposition_df_index)
} else{
(0,1)
}
}
There are a number of things wrong with this code. I'll focus on two things.
variable initialization via pattern matching
val (a, b, c, d) = if (someCondition) doThis()
else doThat()
In this example 4 different variables, a, b, c, and d, are created and initialized. The compiler recognizes that they grouped in a 4-tuple and makes the pattern match if the right side of the equals = returns a 4-tuple. So this only works if both doThis() and doThat() return the same thing, i.e. a 4-tuple with the same type pattern.
None is part of Option
If a variable might be None then that variable's type is Option[X] where X is the type of the variable if it is not None.
val extra_params_map: Option[Map[Int,Int]] = if (extra_params.isEmpty) None
else Some(extra_params.toMap)
Notice that Some() is the compliment of None and the result type is Option. In this case it is Option[Map[Int,Int]] assuming that extra_params.toMap returns a Map[Int,Int].

Why does wrapping values in a code block change my typed numbers into Doubles?

If I call this with 3 I get back an Int-typed return as I expect.
def determineKind( a:Int ):Any = {
if( a < 5 )
a.toInt
else if(a<50)
a.toLong
else if(a<100)
a.toFloat
else
a.toDouble
}
If I call this with 3, I get back a Double.
def determineKind2( a:Int ):Any = {
val aResult = { if( a < 5 )
a.toInt // Execution flows here
else if(a<50)
a.toLong
else if(a<100)
a.toFloat
else
println("Oops!") // Never executed--yet I get a Double back!
a.toDouble
}
aResult
}
Why? I don't want the Double. (The real function uses a match/case block, which also seems to convert any of these numerical types to Double.)
Something about wrapping things in a code block triggers the unwanted type change to Double.
Why is that?
You problem lies in how you defined the if block, effectively, in determineKind2, a.toDouble is always assigned to aResult and the entire result of the if block is discarded.
The illustration of what is happening:
def block = {
if(condition)
v1
else
println(v2)
v2
}
Always returns v2. This happens because the same code using explicit curly braces would be this:
def block = {
if(condition) {
v1
} else {
println(v2)
}
v2
}
Notice how v2 is outside the if block. In case statement block on the other hand:
condition match {
case true => v1
case _ =>
println(v2)
v2
}
The same doesn't happen above, the blocks in cases are ended by the start of another case in the same scope depth.
As a side note: indentation doesn't have any effect in how blocks are compiled.
This is a tricky situation where numeric widening comes into play. In the first example, you are stating the return type, Any, and thus there is no need to widen any of the types. In the second case, val aResult = you are asking Scala to infer the type of the if-expression, and it will avoid to infer Any and instead decide to widening the individual types numerically to a Double. Often this widening is what you'd want, e.g. say you write Seq(1, 2.3, 4.5) - you'd expect that to be a Seq[Double] and not Seq[Any].
If you define the type of aResult, you ask Scala to accept the unspecific type of Any:
def determineKind(a: Int): Any = {
val res: Any /* ! */ = if (a < 5)
a.toInt
else if (a < 50)
a.toLong
else if(a < 100)
a.toFloat
else
a.toDouble
res
}
assert(determineKind(3).isInstanceOf[Int])
Numeric widening appears in section 6.26.1 of the Scala Language Specification:
If e has a primitive number type which weakly conforms to the expected type, it is widened to the expected type using one of the numeric conversion methods toShort, toChar, toInt, toLong, toFloat, toDouble defined here.
Greg, this block below returns value of type Double because the last thing you do in it is calling toDouble method on a.
val aResult = {
if( a < 5 )
a.toInt // Execution flows here
else if(a<50)
a.toLong
else if(a<100)
a.toFloat
else
println("Oops!") // Never executed--yet I get a Double back!
a.toDouble // <---- this line is not a part of if else expression
}
That's a good reason why to use curly braces, so you can prevent mistakes like this.

Using Option with cleaner code

Apologies if this is a newbie question...
In Scala I understand that it is preferred to use an Option rather than returning null when you have a function which returns an instance but could potentially return nothing. I understand that this makes it better with regards to safety, because you are not passing null references around, and risking NullPointerException somewhere down the line.
However, is there a cleaner way to handle options than using pattern matching?
The syntax I end up using is the following:
val optObj : Option[MyObject] = myFunctionThatReturnsOption
optObj match {
case Some(obj) => {
//my code using obj
}
case None => _
}
In reality all this doing is the equivalent of the Java version:
MyObject obj = myMethodThatCanReturnNull()
if (obj != null) {
//my code using obj
}
Is there some other way to avoid all this boilerplate in Scala when using Option instead of null references? All I want to do is execute a piece of code as long as the Option contains some object (i.e. is not None).
Use foreach, getOrElse and/or map if you want to work in a more consistent way. Here's some use cases and what I'd do:
//I want to get a non-null value and I have a sane default
val result = myOption getOrElse 3
//I want to perform some side effecting action but only if not None
myOption foreach{ value =>
println(value toString ())
}
//equivalently
for(value <- myOption){
//notice I haven't used the "yeild" keyword here
}
//I want to do a computation and I don't mind if it comes back as an Option
val result = for(value <- myOption) yield func(value)
val equivalent = myOption map func
The third example will use map in both cases.
It gets really interesting when you can mix and match things in a "for comprehension" (Google term.) Let's say that func also returns an Option but I only want things working in specific cases:
val result = for{
value <- myOption if value > 0
output <- func(value)
} yield output
Now I get back an Option but only if myOption contained an integer that was greater than zero. Pretty nifty stuff, no?
You can use foreach if you just want to perform some side-effecting operation with the value:
optObj.foreach(obj => {
//my code using obj
})
if you have some other use case you should use some other method on Option like map, filter or getOrElse.
Of course, the way I usually use options if I only care about present value is foreach:
optObj.foreach { obj =>
//...
}
Having said this, there are a lot of other options (which #wheaties enlisted) and some people keep battling about the true one.
You can use the flatMap-method pretty well with Option. Like hier:
case class Player(name: String)
def lookupPlayer(id: Int): Option[Player] = {
if (id == 1) Some(new Player("Sean"))
else if(id == 2) Some(new Player("Greg"))
else None
}
def lookupScore(player: Player): Option[Int] = {
if (player.name == "Sean") Some(1000000) else None
}
println(lookupPlayer(1).map(lookupScore)) // Some(Some(1000000))
println(lookupPlayer(2).map(lookupScore)) // Some(None)
println(lookupPlayer(3).map(lookupScore)) // None
println(lookupPlayer(1).flatMap(lookupScore)) // Some(1000000)
println(lookupPlayer(2).flatMap(lookupScore)) // None
println(lookupPlayer(3).flatMap(lookupScore)) // None
Here's a great reference for Scala best practices regarding options:
http://blog.tmorris.net/posts/scalaoption-cheat-sheet/index.html