I am Peter Pilgrim. I watched Martin Odersky create a control abstraction in Scala. However I can not yet seem to repeat it inside IntelliJ IDEA 9. Is it the IDE?
Here is a solution without the StackOverflowError
.
scala> class ConditionIsTrueException extends RuntimeException
defined class ConditionIsTrueException
scala> def repeat(body: => Unit) = new {
| def until(condition: => Boolean) = {
| try {
| while(true) {
| body
| if (condition) throw new ConditionIsTrueException
| }
| } catch {
| case e: ConditionIsTrueException =>
| }
|
| }
| }
repeat: (body: => Unit)java.lang.Object{def until(condition: => Boolean): Unit}
scala> var i = 0
i: Int = 0
scala> repeat { println(i); i += 1 } until(i == 3)
0
1
2
scala> repeat { i += 1 } until(i == 100000)
scala> repeat { i += 1 } until(i == 1000000)
scala> repeat { i += 1 } until(i == 10000000)
scala> repeat { i += 1 } until(i == 100000000)
scala>
According to Jesper and Rex Kerr here is a solution without the Exception.
def repeat(body: => Unit) = new {
def until(condition: => Boolean) = {
do {
body
} while (!condition)
}
}
You don't need the 2nd pair of braces, the usage should be:
repeatLoop (x) until (cond) //or...
repeatLoop {x} until {cond}
And not:
repeatLoop {x} { until(cond) } //EXTRA PAIR OF BRACES
The error means that Scala thinks you are trying to call a method with a signature something like:
def repeatLoop(x: => Unit)(something: X) //2 parameter lists
And can find no such method. It is saying "repeatLoop(body)" does not take parameters. A full code listing for the solution probably looks something a bit more like:
object Control0 {
def repeatLoop(body: => Unit) = new Until(body)
class Until(body: => Unit) {
def until(cond: => Boolean) {
body;
val value: Boolean = cond;
if (value) repeatLoop(body).until(cond)
}
}
def main(args: Array[String]) {
var y: Int = 1
println("testing ... repeatUntil() control structure")
repeatLoop {
println("found y=" + y)
y += 1
}.until(y < 10)
}
}
There are two useful observations to make here:
StackOverflowError
for long iterations (try while (y < 10000)
)until
seems the wrong way round to me (it would be more natural to stop when the condition becomes true, not carry on while it is true). How about a one liner for repeat until.
def repeat(b: => Unit) = new AnyRef {def until(c: => Boolean) {b; while (! c) b}}
Which, for example, gives:-
scala> repeat {
| println("i = "+i)
| i+=1
| } until (i >= 10)
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
As above yet recursive :)
def repeat(b: => Unit) = new {def until(c: => Boolean) = { b; if (c) until(c) }}
var i = 0
repeat {
println(i)
i+=1
} until (i < 10)
It's @tailrec optimized too.
Llove scala :)