Closed domenic closed 5 years ago
Some prior art:
union
and |
, intersection
and &
, difference
and -
, and symmetric_difference
and ^
.set_union
, set_intersection
, set_difference
, and set_symmetric_difference
.union
, intersection
, difference
, and symmetric_difference
.addAll
and removeAll
, but lacks the other operations and non-destructive versions. However:union
, intersection
, difference
, and symmetric_difference
.union
, intersection
, difference
, and disjunction
(which is definitely wrong).UnionWith
, IntersectWith
, ExceptWith
, and SymmetricExceptWith
.union
and |
, intersection
and &
, difference
and -
, and ^
which lacks a named alias.union
, intersection
, subtracting
, and symmetricDifference
.Edit, 2018-05-03: adding some less common languages for completeness. Note that I'm only including languages which have a built-in way of performing symmetric difference which doesn't need to be composed from parts.
union
, intersect
, setdiff
, and symdiff
.union
, intersection
, difference
, and symdiff
.union
, intersect
, setdiff
, and setxor
.ord_union
, ord_intersection
, ord_subtract
, and ord_symdiff
.union
, intersection
and intersect
, setdifference
, and symmdifference
.union
, intersect
, minus
, symmdiff
.union
, intersection
, difference
, symmetric_difference
.join
, meet
, diff
, sdiff
.I think the pattern is pretty clear 🤓 "Be like everyone else, or be like Java".
Clojure and Scala also follow the same pattern:
https://clojuredocs.org/clojure.set
union
, intersect
, difference
https://docs.scala-lang.org/overviews/collections/sets.html
union
, intersect
, diff
I agree that it'd be nice to pick a theme and stick to it.
I think there's a lot of value in aligning with mainstream languages as it's easier for a developer to transition between languages. I'd be +1 on just going with the set theoretic names, even though the names aren't quite ergonomic.
Sigh. In my ten years of spec-dev, I've learned that precedent is extremely important; it's often much better to go with a familiar solution over a slightly more optimal but brand-new one. I've also been pretty consistent in JS with my "just do it like Python does" position. ^_^ But this is the rare case where I think following those principles gives a bad enough result that it's worth violating them.
union
and intersection
are okay; intersection
is a bit long, but it's fine. difference
doesn't communicate the directionality well enough; its use in English doesn't carry a directionality. symmetricDifference
is both incredibly long (19 characters!) and contains a hard-to-spell word; its only benefit is that we no longer care about the directionality of the operation.
Sure, Python used these names (and with an _
, making it 20 characters!), but in my experience using sets, I have never written out a.symmetric_difference(b)
, because a ^ set(b)
is so much easier to write. In other words, Python is cheating, by having everything use single-char ops; the only reason to use the named methods is if you want the second argument to be an arbitrary iterable, and don't feel like manually casting it. Thus the ergonomics of the names don't have much of an effect actually.
I agree that having a consistent naming theme is useful, tho, so I suggest we just go with the bitwise names. Python is also precedent for this; they just spell them as operators rather than as names. and
/or
/minus
/xor
are all short and easy to understand, and minus
in particular has the correct directionality built in from the English meaning.
(I personally occasionally stumble with and
, thinking it means "the elements of A and B", aka or
, but then just remember how the &
operator works. Nothing's perfect, shrug.)
In other words, Python is
cheating
, by having everything use single-char ops
Maybe makes sense add availability to override binary math ops? For example, add Symbol.xor
(or Symbol.symmetricDifference
), on binary bitwise operators evalation, before converting the left arg to int32 check is this object or not, if it's an object try to get @@xor
property and it's exists convert a ^ b
to a[Symbol.xor].call(a, b)
?
Note: I am absolutely not suggesting that we do anything like add new operator semantics. My point is just that Python gives the operations two names - a long logical-operation name as a method, and a very short bitwise-op name as an operator. So saying that Python only provides logical-op as a precedent is incorrect; it also provides a bitwise-op precedent for naming the operations. In JS we'd just use the names of the bitwise ops, rather than their operator forms, precisely because we don't have operator overloading.
Operator overloading is definitely out of scope for this proposal. I'd like to keep this discussion focused on picking a good name for the set methods.
It's just a thought out loud -)
I knew immediately what union, intersection, difference
meant in context of a set (not sure about symmetricDifference
).
However or, and, minus, xor
I'd have to look up (or at least think about) every time I'd use them since those are not terms I'm familiar with (in context with a set) even though they make sense if you think on set item level.
So I'd go with union, intersection, difference
(or slight naming variations on those).
union
, intersection
, difference
, symmetricDifference
.
union
, intersection
and symmetricDifference
are all symmetric, in that changing the order of the operands doesn't change the result. For difference
it does, yet the common English usage of the word 'difference' is the symmetrical one. Therefore I don't think difference
is the right method name for this non-symmetrical operation, and I think a non-symmetrical word like except
, while not in a clear theme, would be better. It clearly indicates that the result will depend on the order of the operands.
I'd follow Python and ruby conventions
Maybe offtopic, but if you use TypeScript and IDE with sensible autocomplete - the length of method name matters a lot less.
union
, intersection
, difference
, symmetricDifference
are thus easily distinguishable one from each other (as even their first letter is different). Plus such naming has precedence in both Python and C++.
As for Python (and Ruby, and Scala) "cheating" - well one more reason to consider operator overloading (outside of this proposal, of course). So that JS will learn to cheat too ;)
.and()
is ambiguous: it could be interpreted to mean either union
(“all the elements in A and all the elements in B”) or intersection
(“elements in A and in B”), depending on how you look at it.
symmetricDifference
is not the easiest method name to type, but it has precedent in set theory and other programming languages. I don’t think this one unfortunate name is a good reason to switch to bitwise names.
Well, union
and intersection
are pretty obvious. or
and and
are rarely used in this context.
Arguments raised against symmetricDifference
is its length, though, majority agrees on it, so I will change proposal today.
I'm still concerned with difference
(it lacks directionality, is long name for common operation) and I'm in favor of following .NET here - .except
is obvious in it's meaning and directionality.
Proposal for another theme: inEither
, inBoth
, notIn
, notInBoth
Short, simple, English meaning immediately accords with technical meaning, the one directional operation reads properly (A.notIn(B)
). No precedent, but I've already argued for the badness of the existing precedent. ^_^
(I'm fine with union
and intersect
; if paired with subtract
and symDiff
my concerns are mollified.)
I'm still concerned with difference (it lacks directionality, is long name for common operation) and I'm in favor of following .NET here - .except is obvious in it's meaning and directionality.
If we're going with symmetricDifference
, it seems surprisingly inconsistent to not use difference
.
All js functions already follow a theme. Look at the array functions. They are all verbs. So it makes more sense to use union
, intersect
and diff
.
"union" can be either a verb or noun, and "intersect" (the verb) is shorter than "intersection"; this suggests that using verbs might be a win.
We discussed this in length at the TC39 meeting in [May]. While we acknowledge that symmetricDifference
is a terrible name, there is substantial amount of precedence in other languages helping consistency across languages. There's also significant community feedback (based on this thread) that this sort of set theoretic naming is preferred.
We considered the alternatives proposed here and didn't find them to be better than the set theoretic names (for reasons listed in this thread, for example, and
is too ambiguous).
I'm going to close this out as I think we've discussed most of the alternatives and haven't been convinced that these are better. Please comment if you have an alternative that's better than the ones discussed.
length of method name matters a lot less.
We shouldn't forget about minification. Although one might argue "just use Wasm", which is a fair (and maybe even solid) point, as all run-times that will support these methods will already support Wasm
This is a continuation of https://github.com/tc39/proposal-set-methods/issues/20#issuecomment-368317865.
Currently, according to the recently closed issues (but not according to the readme??) we have the following "themes" chosen for method names:
I think we shouldn't mix and match: