Reputation: 2928
I have the following Code.
import scala.collection.mutable.MutableList
val x = MutableList[Int]()
(1 to 10).foreach(x+=1)
I get the java.lang.IndexOutOfBoundsException: 1
error.
but,
(1 to 10).foreach(println) this does not throw any error.
the indexOutOfBoundException
can be solved by using lambda Operator as follows:
(1 to 10).foreach(_ => x+=1)
Everything works fine with this.
My questions are :
1. Why do i need to use lambda operator in first case unlike second one?
2. Why the compiler throws IndexOutOfBoundException, i suppose this is not the correct context for this Exception.
Upvotes: 4
Views: 179
Reputation: 29548
What happens is a few little conveniences in the library conspiring to bite you.
foreach signature is
def foreach(f: A => Unit): Unit
In your case, A
is Int
, so it needs a function which takes an Int and returns Unit. Fine with println
. Note you have just written println
, not println(something)
, which would not have been a function.
One would expect x += 1 to be just an instruction, so it would have type Unit
, not a function, not a valid argument of foreach, and one would get a helpful compile-time error. But +=
in MutableList
actually returns the list, which is convenient as it makes chaining operations easier:
def +=(elem: A): this.type
So the type of x+= 1 is MutableList[Int]. One will still expect a compilation error, not a function. Except that MutableList
s (all Seq
s actually) are functions, with Int parameters, returning the type of the Seq's elements. The function simply returns the i-th element. Again, that may be convenient, you may simply pass the seq where a function is expected, instead of having to write i => seq(i)
. Now you have a function, with an Int parameter, what foreach expects.
Still, it does not returns Unit, but Int. However, scala will accept that as an Int => Unit
, just discarding the value. So it compiles.
Now to what it does: first, it evaluates the argument in foreach, so it calls x+=1
, getting the list x, which now contains an element. It will then call this function, which is the access to the i-th element with arguments ranging from 1 to 10). Doing that, it would not add values to the list, but just access elements at the given indexes. It then fails immediately, as the list contains just one element, at index 0
, so calling with 1
throws the IndexOutOfBoundException
.
Upvotes: 5