Maybe I can elaborate.
As I understand it, the source of the bug is that while a user is iterating over the List in MyGroup.members, the List get’s replaced which kills the streaming operations (.filter, .forEach, etc.).
Your solution is to have all Rules developers modify their Rules to save MyGroup.members to a local variable so that they have a local copy of the List which prevents the error from appearing when the List get’s replaced.
My question was whether GroupItem.getMembers() could be modified to return a static copy of the List, thereby removing the imposition on the Rules developers to know and understand this subtle internal implementation details in order to avoid this cryptic error.
In short, almost everyone is currently susceptible to this error and there are hundreds of examples that are susceptible to this error as currently written. But if MyGroup.getMembers() returned a List that doesn’t change out from under us it would fix all of this existing code and future code without requiring a change to the Rules code itself.
I’m not certain this is feasible because I’m only guessing at how the streaming operations in Xtend work (seems like it makes repeated calls to getMembers() instead of calling it once and streaming from that?). But this is a long existing problem that I believe will also be a problem in Scripted Automation. If there is a way we can avoid this problem through a modification to getMembers(), it would be better (IMHO) than the pretty significant amount of work required to write some docs, fix the tutorials, and field the problems like Crispin’s that will continue to crop up as long as we cannot reliably have lines like: MyGroup.members.filter[door | door == CLOSED]
.
I doubt it’s a read only copy, but what happens is when a new update occurs, a new list is created and replaces .members. By saving .members to a local variable you avoid having the List changed out from under you.
You would never be changing the Group membership by adding/removing Item to the List returned by .members anyway though. It would get wiped out on the next update and adding an Item to a Group requires more modification to the Item Registry that would be skipped if you just added an Item to the List returned by .members.
You can dynamically add an Item to a Group using MyGroup.addMember(myItem)
.
An Item, no matter how you get to it isn’t really the Item. It’s a pointer to the Item. The real Item resides in the Item registry. You don’t “update” an Item. You postUpdate to the Item. MyItem.state = ON is not a valid way to set the state of an Item (though sometimes it works?). Anyway, you are always working with a copy of the original Item.
Interesting note, this is why you cannot use the Item Object as the key in a HashMap (for example). You are not guaranteed to get an Item Object that has the same hash value so from run run of the rule to the next you may no longer be able to access the value in the map. So always use the Item name instead of the Item object in Maps.