2

Can you please give me an example when to use OrderedSet instead of Set? I've run a couple of tests and even tho the immutable-js documentation says

Iteration order of a Set is undefined, however is stable

it seems element order within Set is always the same as the one in which elements were added. That's what seems to be the sole benefit of the OrderedSet structure:

A type of Set that has the additional guarantee that the iteration order of values will be the order in which they were added.

dube
  • 4,898
  • 2
  • 23
  • 41
sKopheK
  • 149
  • 13
  • Thanks for the question, you certainly suprised the (recently reorganized) maintainers! I think you are correct and OrderedSet is redundant. I'll keep you updated how the slack discussion turns out – dube Jan 05 '21 at 12:25

1 Answers1

2

It coincidally does add elements at the end, but it is not guaranteed to always be that way. It might change in the next release and it does not always have to be predictable. All it promises is to be stable across multiple iterations over the same data. To be honest, I can't see any useful use case for OrderedSet. Depending on the needs, List, Map or OrderedMap or even Set are better suited.

If you manage to update a Set, it can change the order. Again, this is usually a bad choice for a data structure and you probably should rearrange your data structure, e.g. use OrderedMap or List instead.

The following sample shows that the order can be a bit unexpected:

function modifySet(set) {
  set = set.add(0);
  set = set.add(1);
  set = set.add(2);
  return set.remove(0);
}

let unorderedSet = Immutable.Set([4,5]);
unorderedSet = modifySet(unorderedSet);
console.log('Set:');
for (const value of unorderedSet) {
  console.log(value);
}

let orderedSet = Immutable.OrderedSet([4,5]);
orderedSet = modifySet(orderedSet);
console.log('OrderedSet:');
for (const value of orderedSet) {
  console.log(value);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.12/immutable.js"></script>

Since you can modify keys (!) of a set, it can reorder the elements too:

let set = Immutable.Set([ Immutable.Map({b:1, a:true}), Immutable.Map({b:2,a:true}), Immutable.Map({b:3,a:true}) ])
  .map((t) => {
  if (t.get('b') === 2) return t.set('a', false);
  return t;
  });

console.log('2 is now at the end');
console.log(set.toJS());
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.12/immutable.js"></script>

To add insult to injury, there is a bug in ImmutableJs RC12, which makes OrderedSet behave in the same way (moving the updated element to the end of the list). That one is already fixed in the (so far) unreleased upcoming 4.0 release.

Ok that was an interesting excursion, you made us (the loose group of maintainers) look again into how this rarely used structure works.

dube
  • 4,898
  • 2
  • 23
  • 41
  • "*I can't see any useful use case for `OrderedSet`*" - I would assume an append-only list that also provides a `O(1)` contains-element check – Bergi Jan 05 '21 at 20:11
  • @Bergi And then read on to "other collection types are better suited". Remember the context is ImmutableJS, not generic collection types. It is (due to it's immutability) most often used for state of ReactJs. If you care about order and not just it's stability, you really should split it into identifier and potentially changing `value`, aka use `OrderedMap`. Or use a Map and a separate Set (or even native JS set) wherever you need). While [I guess] we all see the theoretical use case, _I_ claim it's likely bad data design if you end up choosing OrderedSet for an app state. – dube Jan 06 '21 at 07:54