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.
Related
I recently picked up interests in functional programming, and I'm working with some toy script.
One example is, taking a list of integers, adding them up in sequence, and get the index when the rolling sum reaches a certain value, say -1.
This is what I have now:
#tailrec
def someFunc(currentSum: Int, list: List[Int], index: Int): Int = {
if (currentSum == -1) return index
// Return -1 if the value is never reached
if (index >= list.length) return -1
val value = list(index)
someFunc(currentSum + value, list, index + 1)
}
This works, and if the rolling sum never reaches -1, function will return -1.
I'm not exactly happy with returning -1 in this case, after some readings, I was introduced to the concept of Option, basically I could have Some value or None. I figured this might be the proper solution in this scenario, so I changed my code to this:
#tailrec
def someFunc(currentSum: Int, list: List[Int], index: Int): Option[Int] = {
if (currentSum == -1) return Some(index)
if (index >= list.length) return None
val value = list(index)
someFunc(currentSum + value, list, index + 1)
}
Now my question is, is there anything I can do to avoid adding Some(index) in the 3rd line? In this case it seems trivial, but for more complex situation, it seems a bit unnecessary to add Some everywhere down in the chain.
Also I'm also wondering if this is the proper functional way to handle this type of situation?
What you are asking is this: ""I should just be able type return index instead of typing return Some(index), and scala-compiler should understand that since this function returns a Option, so I actually mean the latter"".
it seems a bit unnecessary to add Some everywhere
It is not unnecessary. If what you ask is fulfilled, this will result in ambiguity. Consider this scenario:
def hypotheticalFunction(....): Option[Option[Int]]: = {
if (some-condition ) return None --> ambigious
// more code
}
Does the return None mean return Some(None) or return None? We have no way of knowing.
==========================================
Also I'm also wondering if this is the proper functional way to handle this type of situation?
I can think of at least 2 improvements:
Generally return statements are discouraged, code-readability can take a setback by arbitrary breaking of function flow by a return. You can use this:
if (condition) Some(index)
else if (condition) None
else {
}
Since earlier parts of list is not needed in recursive calls, you can only send the tail of the the list to the recursive function. In this way, you won't have to iterate the list by calling list(index). Some snippet:
#tailrec
def someFunc(currentSum: Int, list: List[Int], index: Int): Option[Int] = {
if (currentSum == -1) Some(index)
else if (list.isEmpty) None
else {
val value = list.head
someFunc(currentSum + value, list.tail, index + 1)
}
}
Not sure what you mean by "everywhere down the chain". There are pretty much just two cases - either Some or None. And yeah, you have to specify which is which.
A pattern match can make this case separation a bit clearer (it also fixes a problem with your implementation making it quadratic: List is a link list, and list(index) is linear, don't do that):
def someFunc(
list: List[Int],
currentSum: Int = 0,
index: Int=0
): Option[Int] = list match {
case _ if currentSum == -1 => Some(index)
case Nil => None
case head :: tail => someFunc(tail, currentSum + head, index+1)
}
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 am a newbie to scala and I am writing scala code to implement pastry protocol. The protocol itself does not matter. There are nodes and each node has a routing table which I want to populate.
Here is the part of the code:
def act () {
def getMatchingNode (initialMatch :String) : Int = {
val len = initialMatch.length
for (i <- 0 to noOfNodes-1) {
var flag : Int = 1
for (j <- 0 to len-1) {
if (list(i).key.charAt(j) == initialMatch(j)) {
continue
}
else {
flag = 0
}
}
if (flag == 1) {
return i
}
}
return -1
}
// iterate over rows
for (ii <- 0 to rows - 1) {
for (jj <- 0 to 15) {
var initialMatch = ""
for (k <- 0 to ii-1) {
initialMatch = initialMatch + key.charAt(k)
}
initialMatch += jj
println("initialMatch",initialMatch)
if (getMatchingNode(initialMatch) != -1) {
Routing(0)(jj) = list(getMatchingNode(initialMatch)).key
}
else {
Routing(0)(jj) = "NULL"
}
}
}
}// act
The problem is when the function call to getMatchingNode takes place then the actor dies suddenly by itself. 'list' is the list of all nodes. (list of node objects)
Also this behaviour is not consistent. The call to getMatchingNode should take place 15 times for each actor (for 10 nodes).
But while debugging the actor kills itself in the getMatchingNode function call after one call or sometimes after 3-4 calls.
The scala library code which gets executed is this :
def run() {
try {
beginExecution()
try {
if (fun eq null)
handler(msg)
else
fun()
} catch {
case _: KillActorControl =>
// do nothing
case e: Exception if reactor.exceptionHandler.isDefinedAt(e) =>
reactor.exceptionHandler(e)
}
reactor.kill()
}
Eclipse shows that this code has been called from the for loop in the getMatchingNode function
def getMatchingNode (initialMatch :String) : Int = {
val len = initialMatch.length
for (i <- 0 to noOfNodes-1)
The strange thing is that sometimes the loop behaves normally and sometimes it goes to the scala code which kills the actor.
Any inputs what wrong with the code??
Any help would be appreciated.
Got the error..
The 'continue' clause in the for loop caused the trouble.
I thought we could use continue in Scala as we do in C++/Java but it does not seem so.
Removing the continue solved the issue.
From the book: "Programming in Scala 2ed" by M.Odersky
You may have noticed that there has been no mention of break or continue.
Scala leaves out these commands because they do not mesh well with function
literals, a feature described in the next chapter. It is clear what continue
means inside a while loop, but what would it mean inside a function literal?
While Scala supports both imperative and functional styles of programming,
in this case it leans slightly towards functional programming in exchange
for simplifying the language. Do not worry, though. There are many ways to
program without break and continue, and if you take advantage of function
literals, those alternatives can often be shorter than the original code.
I really suggest reading the book if you want to learn scala
Your code is based on tons of nested for loops, which can be more often than not be rewritten using the Higher Order Functions available on the most appropriate Collection.
You can rewrite you function like the following [I'm trying to make it approachable for newcomers]:
//works if "list" contains "nodes" with an attribute "node.key: String"
def getMatchingNode (initialMatch :String) : Int = {
//a new list with the corresponding keys
val nodeKeys = list.map(node => node.key)
//zips each key (creates a pair) with the corresponding index in the list and then find a possible match
val matchOption: Option[(String, Int)] = (nodeKeys.zipWithIndex) find {case (key, index) => key == initialMatch}
//we convert an eventual result contained in the Option, with the right projection of the pair (which contains the index)
val idxOption = matchOption map {case (key, index) => index} //now we have an Option[Int] with a possible index
//returns the content of option if it's full (Some) or a default value of "-1" if there was no match (None). See Option[T] for more details
idxOption.getOrElse(-1)
}
The potential to easily transform or operate on the Collection's elements is what makes continues, and for loops in general, less used in Scala
You can convert the row iteration in a similar way, but I would suggest that if you need to work a lot with the collection's indexes, you want to use an IndexedSeq or one of its implementations, like ArrayBuffer.
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.