Reputation: 21590
Example
This test fails because each
does not modify the list's elements.
void test_each_DoesNotModifyListElements() {
List<String> list = ["a", "b", "c"]
list.each { it = it + "z" }
assert ["az", "bz", "cz"] == list
}
This test passes because collect
returns a new list with modified elements.
void test_collect_ReturnsNewListWithModifiedElements() {
List<String> list = ["a", "b", "c"]
list = list.collect{ it + "z" }
assert ["az", "bz", "cz"] == list
}
Assumption
At this point, I am assuming that each
does not modify the list's elements because I have written the tests below and I am assuming that that's what the tests are telling me. Please correct me if I am wrong.
void test_each_DoesNotModifyListElements1() {
List<String> list = ["a", "b", "c"]
list.each { it + "z" }
assert ["az", "bz", "cz"] == list
}
void test_each_DoesNotModifyListElements2() {
List<String> list = ["a", "b", "c"]
list.each { it = it + "z" }
assert ["az", "bz", "cz"] == list
}
void test_each_DoesNotModifyListElements3() {
List<String> list = ["a", "b", "c"]
list = list.each { it = it + "z" }
assert ["az", "bz", "cz"] == list
}
Question
So the question is: as a Groovy beginner, how should I have known beforehand, meaning before writing tests and googling, that each
does not change the list's element?
By reading the documentation?
Groovy each documentation: Iterates through an aggregate type or data structure, passing each item to the given closure. Custom types may utilize this method by simply providing an "iterator()" method. The items returned from the resulting iterator will be passed to the closure.
Oftentimes, I end up spending a lot of time trying things out and googling for answers. Shouldn't there be a more efficient way? Is there?
Upvotes: 3
Views: 5365
Reputation: 9061
@Max has provided an excellent answer above. My 2 cents to go with it. The variables or references are actually pass by value in java. Understanding this is also important. Please note, the object itself is not copied only the reference to it is copied.
Now lets come back to the list. It has references to all the objects within it. When you call each
on the list, a new reference is created pointing to the same object and passed to the each
method. So even if you make this newly created reference variable point to a different object, the reference in the list is still unaltered and pointing to the same old object.
Upvotes: 1
Reputation: 26152
Well, that is not far from Java/Groovy programming basics. There are Objects, and there are Variables. Variable can hold a "link" to the object, called a reference. So basically, using a variable you can access the real object stored in depths of computer memory.
Whenever you alter the Variable (that is, assign to it something), you never modify the real object. Instead, the variable begins to point to some different Object.
Now, looking at documentation again:
Iterates through an aggregate type or data structure, passing each item to the given closure.
That's all it does. It gives you a variable pointing to each item. If you overwrite the local variable you had been given, the variable starts to point to other object and that's it. The list still has the reference to the old object.
That information is the most basical knowledge required to program in Java and similar languages. Usually it is explained at the first pages of manuals/documentations. And because it is that basic, nobody bothers explaining it over and over again for each function where you have some kind of parameter.
Upvotes: 5