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
}
Related
If I replace the first line of the following recursive depth first search function with the lines commented out within the foreach block, it will fail to compile as a tail recursive function (due to the #tailrec annotation) even though the recursion is still clearly the last action of the function. Is there a legitimate reason for this behavior?
#tailrec def searchNodes(nodes: List[Node], visitedNodes: List[Node], end: String, currentLevel: Int) : Int = {
if (nodes.exists(n => n.id == end)) return currentLevel
val newVisitedNodes = visitedNodes ::: nodes
var nextNodes = List[Node]()
nodes.foreach(n => {
/*
if (n.id == end){
return currentLevel
}
*/
nextNodes = nextNodes ::: n.addAdjacentNodes(visitedNodes)
})
if (nextNodes.size == 0) return -1
return searchNodes(nextNodes, newVisitedNodes, end, currentLevel + 1)
}
As the other answer explains, using return in scala is a bad idea, and an anti-pattern. But what is even worse is using a return inside a lambda function (like your commented out code inside foreach): that actually throws an exception, that is then caught outside to make the main function exit.
As a result, the body of your function is compiled into something like:
def foo(nodes: List[Node]) = {
val handle = new AnyRef
try {
nodes.foreach { n =>
if(n.id == "foo") throw new NonLocalReturnControl(handle, currentLevel)
...
foo(nextNodes)
} catch {
case nlrc: NonLocalReturnControl[Int] if nlrc.key == handle => nlrc.value
}
}
As you can see, your recursive call is not in a tail position here, so compiler error is legit.
A more idiomatic way to write what you want would be to deconstruct the list, and use the recursion itself as the "engine" for the loop:
def searchNodes(nodes: List[Node], end: String) = {
#tailrec def doSearch(
nodes: List[(Node, Int)],
visited: List[Node],
end: String
) : Int = nodes match {
case Nil => -1
case (node, level) :: tail if node.id == end => level
case (node, level) :: tail =>
doSearch(
tail ::: node.addAdjacentNodes(visited).map(_ -> level+1),
node :: visited,
end
)
}
doSearch(nodes.map(_ -> 0), Nil, end)
}
I'm not sure exactly what the compiler is thinking, but I think all your return statements will be causing problems.
Using return is an antipattern in scala - you don't need to write it, and you shouldn't. To avoid it, you'll have to restructure your if ... return blocks as if ... value ... else ... other value blocks.
This shape is possible because everything is an expression (sort of). Your def has a value, which is defined by an if ... else block, where the if and the else both have values, and so on all the way down. If you want to ignore the value of something you can just put a new line after it, and the return value of a block is always the value of the last expression in it. You can do that to avoid having to rewrite your foreach, but it would be better to write it functionally, as a map.
I implemented to find max value in the list.
I know that in Scala, You don't have to use 'return', just drop it.
So I wrote like this,
def max(xs: List[Int]):Int={
if(xs.isEmpty) throw new java.util.NoSuchElementException
def f(cur_max:Int, xs:List[Int]):Int={
if(xs.isEmpty)
cur_max // <- it doesn't return value but just keep going below code.
if(cur_max < xs.head)
f(xs.head,xs.tail)
else
f(cur_max,xs.tail)
}
f(xs.head,xs)
}
When it traversed to end of List, it should be returned cur_max value.
However, It just keeps going. Why doesn't it return cur_max.
To fix this problem, I put 'return' expression that Scala doesn't recommend like ('return cur_max').
In Scala it is not enought just to drop value - method returns last evaluated statement. In your case you have two statements:
if(xs.isEmpty)
cur_max
and
if(cur_max < xs.head)
f(xs.head,xs.tail)
else
f(cur_max,xs.tail)
So the result of second expression one gets returned.
To fix it add else statement:
if(xs.isEmpty)
cur_max
else if(cur_max < xs.head)
f(xs.head,xs.tail)
else
f(cur_max,xs.tail)
made several changes. some of them just code style to be more readable like having brackets on if expressions.
def max(xs: List[Int]): Int = {
def f(cur_max: Int, xs: List[Int]): Int = {
if (xs.isEmpty) {
cur_max // <- it doesn't return value but just keep going below code.
} else {
if (cur_max < xs.head) {
f(xs.head, xs.tail)
}
else {
f(cur_max, xs.tail)
}
}
}
if (xs.isEmpty) {
throw new java.util.NoSuchElementException
} else {
f(xs.head, xs.tail)
}
}
basically there are some cases on your inner function, which you named f:
the list is empty -> you should return the current max value
the list is not empty AND the current max is smaller than the first element of the remaining list -> update the current max and call the function with the list tail
the list is not empty AND the current max is >= than the first element of the remaining list -> call the function with the list tail and the same current max
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've got a nested block of a condition, a for loop and try/catch block to return a tuple:
val (a, b) = {
if (...) {
for (...) {
try {
getTuple(conf)
} catch {
case e: Throwable => println(...)
}
}
sys.exit
} else {
try {
getTuple(userConf)
} catch {
case e: Throwable => println(...); sys.exit
}
}
}
If the if condition matches I would like to try x different conf configurations. When getTuple throws an exception, try the next one. When getTuple does not throw an exception, fill the tuple with the result. getTuple returns the tuple (a,b).
Problem: However, the for loop does not exit when getTuple does not throw an exception. I also tried break but that does not work as it should return the tuple and not just exit the for loop.
How can I get this to work?
Instead of throwing Exception, getTuple should evaluate as a Option[Tuple2[T,U]], it has more meaning and does not break the flow of the program.
This way, you can have a for like this:
val tuples: List[Option[Tuple2[T,U]] = for {
c <- configs
} yield getTuple(c)
val firstWorkingConfig: Option[Tuples2[T,U]] = tuples.flatten.headOption
// Exit the program if no config is okay
firstWorkingConfig.getOrElse {
sys.exit
}
Hope this helps
I'd suggest to use more functional features of Scala instead of dealing with loops and exceptions.
Suppose we have a function that throws an exception on some inputs:
def myfn(x: Double): Double =
if (x < 0)
throw new Exception;
else
Math.sqrt(x);
We can either refactor it to return Option:
def optMyfn(x: Double): Option[Double] =
if (x < 0)
None;
else
Some(Math.sqrt(x));
Or if we don't want to (or cannot modify the original code), we can simply wrap it using Exception.Catcher:
def optMyfn(x: Double): Option[Double]
= scala.util.control.Exception.allCatch.opt(myfn(x));
Now let's have a sequence of numbers and we want to find the first one on which the function succeeds:
val testseq: Seq[Double] = Seq(-3.0, -2.0, 2.0, 4.0, 5.0);
We can use Scala's functional features to apply the function to all the elements and find the first Some result as
testseq.toStream.map(optMyfn _).flatten.headOption
It'd work as well without using toStream, but we'd call optMyfn unnecessarily on all the element, instead of just those we need to find the first successful result - streams make the computation lazy.
(Another option would be to use views, like
testseq.view.map(optMyfn _).collectFirst({ case Some(x) => x })
.)
The sys.exit call is kinda misplaced in the if statement. It should be inside the catch clause to allow for a return of tupe if try is successful.
If you want to loop until you get a working tuple a while loop makes more sense. The semantics of a for loop is to evalute the body for all elements you are iterating. Since your goal is to stop after the first which satisfies a condition, a while loop seems much more natural. Of course there would be some more functional alternatives, for instance:
wrap your getTuple in an Option, where None corresponds to an exception.
put the calls to getTuple in some iterable/traversable collection
get the first element which is not None
While I was explaining the concept, Romain Sertelon gave a nice example of the idea...
Another solution is to just wrap the whole block into a method and use return like:
val (a: Type, b: Type) = setup(...)
def setup(...) : (Type, Type) = {
if (...) {
for (...) {
try {
return getTuple(...)
} catch {
...
}
}
sys.exit
} else {
try {
return getTuple(...)
} catch {
case e: Throwable => println(...); sys.exit
}
}
}
I think I should learn more basics of Scala, but that works now for the moment.
Thanks for your answers.
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.