Can we definitely assume no duplicates (your and my change-test will break if could be duplicates; if so, should instead use sets and then convert to list at point of setting attribute)?

If no duplicates, can just do `changed = (oldNodes.size() != newNodes.size()) || !oldNodes.containsAll(newNodes)`?