2
votes

I have the following code, but I can't get it to work. As soon as I place a while loop inside the case, it's returning a unit, no matter what I change within the brackets.

case While(c, body) =>
    while (true) {
      eval(Num(1))
    }
}

How can I make this while loop return a non-Unit type?

I tried adding brackets around my while condition, but still it doesn't do what it's supposed to.

Any pointers?

Update

A little more background information since I didn't really explain what the code should do, which seems to be handy if I want to receive some help;

I have defined a eval(exp : Exp). This will evaluate a function. Exp is an abstract class. Extended by several classes like Plus, Minus (few more basic operations) and a IfThenElse(cond : Exp, then : Exp, else : Exp). Last but not least, there's the While(cond: Exp, body: Exp).

Example of how it should be used;

eval(Plus(Num(1),Num(4)) would result in NumValue(5). (Evaluation of Num(v : Value) results in NumValue(v). NumValue extends Value, which is another abstract class).

eval(While(Lt(Num(1),Var("n")), Plus(Num(1), Var("n"))))

Lt(a : Exp, b : Exp) returns NumValue(1) if a < b.

4
While and do-while don't have return values in scala.vertti
I'm not sure where you're going with this loop. Not only will a while-loop never return a value, but your while loop will never return at all (unless an exception occurs). What do you want to return?thoredge
@thoredge as stated below somewhere, the 'true' condition was for testing purposes. ;) I hope my explaination above will give you a beter idea of what I'm trying to do. Thanks.Sander
I'm not sure what your edit adds to the question. You haven't explained anything about what you want the loop to return.Ken Bloom

4 Answers

9
votes

It's probably clear from the other answer that Scala while loops always return Unit. What's nice about Scala is that if it doesn't do what you want, you can always extend it.

Here is the definition of a while-like construct that returns the result of the last iteration (it will throw an exception if the loop is never entered):

def whiley[T](cond : =>Boolean)(body : =>T) : T = {
  @scala.annotation.tailrec
  def loop(previous : T) : T = if(cond) loop(body) else previous
  if(cond) loop(body) else throw new Exception("Loop must be entered at least once.")
}

...and you can then use it as a while. (In fact, the @tailrec annotation will make it compile into the exact same thing as a while loop.)

var x = 10
val atExit = whiley(x > 0) {
  val squared = x * x
  println(x)
  x -= 1
  squared
}
println("The last time x was printed, its square was : " + atExit)

(Note that I'm not claiming the construct is useful.)

8
votes

Which iteration would you expect this loop to return? If you want a Seq of the results of all iterations, use a for expression (also called for comprehension). If you want just the last one, create a var outside the loop, set its value on each iteration, and return that var after the loop. (Also look into other looping constructs that are implemented as functions on different types of collections, like foldLeft and foldRight, which have their own interesting behaviors as far as return value goes.) The Scala while loop returns Unit because there's no sensible one size fits all answer to this question.

(By the way, there's no way for the compiler to know this, but the loop you wrote will never return. If the compiler could theoretically be smart enough to figure out that while(true) never terminates, then the expected return type would be Nothing.)

7
votes

The only purpose of a while loop is to execute a side-effect. Or put another way, it will always evaluate to Unit.

If you want something meaningful back, why don't you consider using an if-else-expression or a for-expression?

2
votes

As everyone else and their mothers said, while loops do not return values in Scala. What no one seems to have mentioned is that there's a reason for that: performance.

Returning a value has an impact on performance, so the compiler would have to be smart about when you do need that return value, and when you don't. There are cases where that can be trivially done, but there are complex cases as well. The compiler would have to be smarter, which means it would be slower and more complex. The cost was deemed not worth the benefit.

Now, there are two looping constructs in Scala (all the others are based on these two): while loops and recursion. Scala can optimize tail recursion, and the result is often faster than while loops. Or, otherwise, you can use while loops and get the result back through side effects.