I am a newbie scala programmer and came across a weird behavior.
def balanceMain(elem: List[Char]): Boolean =
{
if (elem.isEmpty)
if (count == 0)
true;
else false;
if (elem.head == '(')
balanceMain(elem.tail, open, count + 1);....
Above basically I want to return true if elem.isEmpty and count == 0. Otherwise, I want to return false.
Now above I have read that there is no need to add a return statement in scala. So I have omitted return above. But it doesn't return the boolean. If I add a return statement as return true. it works perfectly. Why is it so?
Also, why is it considered a bad practice to have return statements in scala
It's not as simple as just omitting the return keyword. In Scala, if there is no return then the last expression is taken to be the return value. So, if the last expression is what you want to return, then you can omit the return keyword. But if what you want to return is not the last expression, then Scala will not know that you wanted to return it.
An example:
def f() = {
if (something)
"A"
else
"B"
}
Here the last expression of the function f is an if/else expression that evaluates to a String. Since there is no explicit return marked, Scala will infer that you wanted to return the result of this if/else expression: a String.
Now, if we add something after the if/else expression:
def f() = {
if (something)
"A"
else
"B"
if (somethingElse)
1
else
2
}
Now the last expression is an if/else expression that evaluates to an Int. So the return type of f will be Int. If we really wanted it to return the String, then we're in trouble because Scala has no idea that that's what we intended. Thus, we have to fix it by either storing the String to a variable and returning it after the second if/else expression, or by changing the order so that the String part happens last.
Finally, we can avoid the return keyword even with a nested if-else expression like yours:
def f() = {
if(somethingFirst) {
if (something) // Last expression of `if` returns a String
"A"
else
"B"
}
else {
if (somethingElse)
1
else
2
"C" // Last expression of `else` returns a String
}
}
This topic is actually a little more complicated as described in the answers so far. This blogpost by Rob Norris explains it in more detail and gives examples on when using return will actually break your code (or at least have non-obvious effects).
At this point let me just quote the essence of the post. The most important statement is right in the beginning. Print this as a poster and put it to your wall :-)
The return keyword is not “optional” or “inferred”; it changes the
meaning of your program, and you should never use it.
It gives one example, where it actually breaks something, when you inline a function
// Inline add and addR
def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add
scala> sum(33, 42, 99)
res2: Int = 174 // alright
def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR
scala> sumR(33, 42, 99)
res3: Int = 33 // um.
because
A return expression, when evaluated, abandons the current computation
and returns to the caller of the method in which return appears.
This is only one of the examples given in the linked post and it's the easiest to understand. There're more and I highly encourage you, to go there, read and understand.
When you come from imperative languages like Java, this might seem odd at first, but once you get used to this style it will make sense. Let me close with another quote:
If you find yourself in a situation where you think you want to return early, you need to re-think the way you have defined your computation.
I don't program Scala, but I use another language with implicit returns (Ruby). You have code after your if (elem.isEmpty) block -- the last line of code is what's returned, which is why you're not getting what you're expecting.
EDIT: Here's a simpler way to write your function too. Just use the boolean value of isEmpty and count to return true or false automatically:
def balanceMain(elem: List[Char]): Boolean =
{
elem.isEmpty && count == 0
}
By default the last expression of a function will be returned.
In your example there is another expression after the point, where you want your return value.
If you want to return anything prior to your last expression, you still have to use return.
You could modify your example like this, to return a Boolean from the first part
def balanceMain(elem: List[Char]): Boolean = {
if (elem.isEmpty) {
// == is a Boolean resulting function as well, so your can write it this way
count == 0
} else {
// keep the rest in this block, the last value will be returned as well
if (elem.head == "(") {
balanceMain(elem.tail, open, count + 1)
}
// some more statements
...
// just don't forget your Boolean in the end
someBoolExpression
}
}
Don't write if statements without a corresponding else. Once you add the else to your fragment you'll see that your true and false are in fact the last expressions of the function.
def balanceMain(elem: List[Char]): Boolean =
{
if (elem.isEmpty)
if (count == 0)
true
else
false
else
if (elem.head == '(')
balanceMain(elem.tail, open, count + 1)
else....
Use case match for early return purpose. It will force you to declare all return branches explicitly, preventing the careless mistake of forgetting to write return somewhere.
Related
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
}
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.
I have a string, lets say val mystr = "abcde", and I want to find the minimal substring of mystr which satisfies a given condition. I have to send a string to an external system, so the only way to do this is to iterate through the length of the string and make requests to the external system, and break when the response from the external system returns true
eg.
callExtSystemWith("a") //Returns false
callExtSystemWith("ab") //Returns false
callExtSystemWith("abc") //Returns true
Then my method should return "abc". I read that breaks are not the scala way, so was wondering what is the scala way of achieving this?
Right now I have:
for {end <- 1 to mystr.length)}{
callExtSystemWith(mystr.substring(0,end))
// I Want to break when this is true.
}
Help much appreciated
You can use inits.toStream.reverse.drop(1) (1 to s.length).map(s.take).toStream to create a lazy stream with a, ab, abc, abcd.
Then filter those strings, so that only the ones for which callExtSystemWith returns true are left.
Then get the first string for which callExtSystemWith returns true. Because this is a lazy stream, no unecessary requests will be made to the server once the first match is found.
val s = "abcdefgh"
val strs = (1 to s.length).map(s.take).toStream
strs.filter(callExtSystemWith).headOption match {
case Some(s) => "found"
case _ => "not found"
}
You can also use find instead of filter + headOption
Quite often break can be replaced with find on some sequence
So here is another short solution for this problem:
def findSuitablePrefix(mystr: String): Option[String] =
(1 to mystr.length).view.map(mystr.substring(0, _)).find(callExtSystemWith)
.view makes the evaluation lazy to avoid creating extra substrings.
.map transforms the sequence of indexes into a sequence of substrings.
And .find "breaks" after the first element for which callExtSystemWith returns true is found.
In Scala there are no normal breaks but there are other solutions. The one I like better is to create a function and force a return (instead of a normal break). Something like:
def callAndBreak(mystr:String) : Int = {
for (end <- 1 to mystr.length) {
if ( callExtSystemWith(mystr.substring(0,end)) ) return end
}
end
}
Here I return end but you can return anything
If you want to avoid using return or breaks, you could also use foldLeft:
val finalResult = (1 to mystr.length).foldLeft(false) { (result, end) =>
if(!result) callExtSystemWith(mystr.substring(0, end)) else result
}
However, it is a bit hard to read, and will walk the entire length of the string.
Simple recursion might be a better way:
def go(s: String, end: Int): Boolean = {
if(end >= s.length) false
else {
callExtSystemWith(s.substring(0, end)) || go(s, end + 1)
}
}
go(mystr, 1)
I am doing scala through the functional programming course on coursera. I noticed that the automatic style checker tells me that the use of 'return' is a bad habit. Why is that? To me it seems like the use of return would make the code more readable because any other programmers can instantly see that and what the function is returning.
Example, why is this;
def sum(xs: List[Int]): Int = {
if( xs.length == 0){
return 0
}else{
return xs.head + sum(xs.tail)
}
}
Considered to be worse than this;
def sum(xs: List[Int]): Int = {
if( xs.length == 0){
0
}else{
xs.head + sum(xs.tail)
}
}
I am used to javascript, so that might be a reason why I feel uneasy about it. Still, can anybody make it obvious why the addition of the return statement makes my code worse? If so, why is there a return statement in the language?
In Java, Javascript and other imperative languages if...else is a flow-control statement.
This means you can do this
public int doStuff(final boolean flag) {
if(flag)
return 1;
else
return 5;
}
But you cannot do this
public int doStuff(final boolean flag) {
return if(flag)
1;
else
5;
}
Because if...else is a statement and not an expression. To accomplish this you need to use the ternary operator (strictly speaking the "conditional operator"), something like:
public int doStuff(final boolean flag) {
return flag ? 1 : 5;
}
In Scala, this is different. The if...else construct is an expression, so more akin to the conditional operator in the languages you are used to. So, in fact your code is better written as:
def sum(xs: List[Int]): Int = {
return if(xs.length == 0) {
0
} else {
xs.head + sum(xs.tail)
}
}
Further, the last expression in a function is automatically returned, so the return is redundant. In fact, as the code only has single expressions, the curly brackets are redundant too:
def sum(xs: List[Int]): Int =
if(xs.length == 0) 0
else xs.head + sum(xs.tail)
So, to answer your question: this is discouraged because it is a misinterpretation of the nature if the if...else construct in Scala.
But this is all a little besides the point, you should really be using pattern matching
def sum(xs: List[Int]): Int = xs match {
case Nil => 0
case head::tail => head + sum(tail)
}
This is much more idiomatic Scala. Learn how to use (and abuse) pattern matching and you will save yourself a huge number of lines of code.
I think another answer for the question why
why is the use of return a bad habit in scala
is that return when used in a closure will return from the method not from the closure itself.
For example, consider this code:
def sumElements(xs: List[Int]): Int = {
val ys: List[Int] = xs.map { x =>
return x + 1
}
return ys.sum
}
It can be easily missed that when this code is invoked with sumElements(List(1, 2, 3, 4)) the result will be 2 and not 10. This is because return within map will return from sumElements and not from the map call.
In scala, every line is an expression, not a statement. Statements generally don't have a return value, but expressions do.
The last result of a block will be the returned value, and so the style guide operates on this assumption. A return would be an exceptional exit from a block.
def sum(xs: List[Int]): Int = {
if(xs.isEmpty) return 0
xs.head + sum(xs.tail)
}
The return statement there would cause the function to bail at that return, and generally leads to less understandable code than if you wrote it with the if/else logic, as you did earlier. I believe the rational behind the style decision is to discourage this type of programming as it makes the programs more difficult to understand.
I am working on the Scala Coursera course right now (so I am still very new to the language and the paradigm).
In any case, I have completed the first lesson, but, when I run styleCheck against the code (which is also run as part of the grade), I receive warnings back that I should avoid using return. However, when I don't use return, my if statements just fall through. Here is an example of the code (no hints, per Coursera's honor policy):
if(value == 0) return 1
if(value == 1) return 0
if(some.other.value.is.something) return 0
recursiveCall(some, stuff)
Based on my understanding of the problem, I don't believe I can turn these into if/else's (I did try that, and then my solution wasn't correct). So, I'm stuck as to what possible options there may be. I'm also not understanding why I shouldn't use returns in the first place. Explanations/help on both would be much appreciated.
The return keyword exists in Scala, but you rarely need it.
The return value of a method in Scala is simply the value of the last expression in the method; you can leave out the return keyword.
Note that in Scala, if is an expression and not a statement - it evaluates to a value. For example, you can assign the result of an if expression to a variable:
val result = if (x == 3) 5 else 7
You could rewrite your code like this:
if (value == 0) 1
else if (value == 1) 0
else if (some.other.value.is.something) 0
else recursiveCall(some, stuff)
(assuming that recursiveCall(some, stuff) also returns a value).
Maybe the problem is about the recursion.
One sees this often:
def f(x: X, value: Value): Int = {
def loop(x: X): Int = ??? // some recursive algorithm
value match {
case 0 => 1 // some guard conditions
case 1 => 0
case _ if some.condition => 0
case _ => loop(x)
}
}
That is, some local defs are followed by a small snippet that constitutes the small body of the function.
In particular, a local def is the recursive function to invoke.