convex icon indicating copy to clipboard operation
convex copied to clipboard

Is `disj` necessary anymore?

Open helins opened this issue 4 years ago • 5 comments

Sets are now considered as maps of value -> true. Since it is now possible to do (assoc #{} 42 true), it looks like disj is not needed anymore. It would be more consistent to make dissoc work with sets.

helins avatar May 31 '21 20:05 helins

Sounds sensible. Though Sets are not exactly equals to such maps, they behave differently for various functions (map?).

Might be worth keeping disj as an alias for a unified dissoc for familiarity with Clojure users? Though that would potentially be a violation of the simplicity principle....

mikera avatar May 31 '21 21:05 mikera

On one hand, it is true that you cannot always dissoc on something that you can assoc on (eg. vectors). On the other hand, I see dissoc as having the hability to remove any element. I suspect the only reason Clojure has disj is because you cannot (assoc #{} :foo true). Since we can, I cannot see a valid reason for keeping it. Convex is sufficiently different from Clojure that I wouldn't mind removing it.

helins avatar Jun 02 '21 13:06 helins

After some reflection, I am thinking we should keep this for now for a few reasons:

  • Logically, each of the major collection types has different removal semantics (dissoc a whole entry for Maps, disj a single element for Sets, drop and take for Vectors and Lists)
  • It is familiar to Clojure users
  • There is potentially a slight performance benefit from specialised dissoc vs. disj, since Maps and Sets have different interfaces for removal
  • It gives a bit better type safety and more consistent type signatures

mikera avatar Jul 02 '21 03:07 mikera

Writing doc, I keep bumping into that kind of considerations.

First and foremost, I guess what bothers me most is that sets can use assoc to remove a value while not supporting dissoc. I'd rather prefer removing support for assoc, leaving conj as the idiomatic function.

helins avatar Nov 14 '22 22:11 helins

I think the important thing is the we establish logical abstract types and that core functions work consistently on them.

disj is Set specific, so no problem. It's the inverse of conj in the context of Sets. It also has a very specific usage of converting nil to the empty Set (effectively a Set coercion on the input, since Set functions generally treat nil as the empty Set).

assoc and dissoc seem logically part of an "Associative" abstraction, that maps keys to values. If we take that position, options seem to be:

  1. We could conclude that Set should not be considered Associative, and hence lose both assoc and dissoc.
  2. We could accept that dissoc is not symmetric. It already doesn't work for Vector....
  3. We could make Associative dissoc work the same as disj with Sets.

Alternatively we could say that dissoc is Map specific like disj is Set specific. 4. I think this is current behaviour?

mikera avatar Nov 20 '22 17:11 mikera