Reputation: 2781
How can I initialize a val that is to be used in another scope? In the example below, I am forced to make myOptimizedList
as a var, since it is initialized in the if (iteration == 5){}
scope and used in the if (iteration > 5){}
scope.
val myList:A = List(...)
var myOptimizedList:A = null
for (iteration <- 1 to 100) {
if (iteration < 5) {
process(myList)
} else if (iteration == 5)
myOptimizedList = optimize(myList)
}
if (iteration > 5) {
process(myOptimizedList)
}
}
This may have been asked before, but I wonder if there is an elegant solution that uses Option[A].
Upvotes: 2
Views: 1096
Reputation: 167891
You can almost always rewrite some sort of looping construct as a (tail) recursive function:
@annotation.tailrec def processLists(xs: List[A], start: Int, stop: Int) {
val next = start + 1
if (start < 5) { process(xs); processLists(xs, next, stop)
else if (start == 5) { processLists( optimize(xs), next, stop) }
else if (start <= stop) { process(xs); processLists( xs, next, stop ) }
}
processLists(myList, 100, 1)
Here, you pass forward that data which you would otherwise have mutated. If you need to mutate a huge number of things it becomes unwieldy, but for one or two it is often as clear or clearer than doing the mutation.
Upvotes: 3
Reputation: 7963
There's another technique (perhaps trick in this case) to delay initialization of
myOptimizedList
which is to use a lazy val. Your example is very specific but the principal is still obvious, delay assignment of a val until it is first referenced.
val myList = List(A(), A(), A())
lazy val myOptimizedList = optimize(myList)
for (iteration <- 1 to 100) {
if (iteration < 5)
process(myList)
else if (iteration > 5)
process(myOptimizedList)
}
Note that the case iteration == 5
is ignored.
Upvotes: 2
Reputation: 26566
Seems that you have taken this code example out of the context, so this solution can be not very suitable for your real context, but you can use foldLeft
in order to simplify it:
val myOptimizedList = (1 to 100).foldLeft (myList) {
case (list, 5) => optimize(list)
case (list, _) => process(list); list
}
Upvotes: 8
Reputation: 52681
It's often the case that you can rework your code to avoid the problem. Consider the simple, and common, example here:
var x = 0
if(something)
x = 5
else
x = 6
println(x)
This would be a pretty common pattern in most languages, but Scala has a better way of doing it. Specifically, if-statements can return values, so the better way is:
val x =
if(something)
5
else
6
println(x)
So we can make x
a val after all.
Now, clearly your code can be rewritten to use all val
s:
val myList:A = List(...)
for (iteration <- 1 to 5)
process(myList)
val myOptimizedList = optimize(myList)
for (iteration <- 5 to 100)
process(myOptimizedList)
But I suspect this is simply an example, not your real case. But if you're unsure how you might rearrange your real code to accomplish something similar, please show us what it looks like.
Upvotes: 2