Christopher Barker writes:
But to a couple points:
Why do you want to add them? The point of an ABC is that it is Abstract. This doesn't just mean "can't instantiate", it also means "only the defining features."
Well, Python's history makes all this a bit backward -- most (all?) of the ABCs existed in concrete form before there wre abstract versions.
"History" -- that aspect of human recollection that makes everything a bit backward. ;-)
But anyway, as I understand it, "abstract" means "not implemented", which is completely separate from "only the defining features" -- ABCs define the API, not the feature set.
This is also historical, as you point out:
And the fact is that Python has a somewhat arbitrary mix of operators implemented by dunders, protocols implemented by dunders (like the len() function) and regular old methods -- all of these are in the ABCs.
So I don't think there's any clear principle here -- do we want .union() and friends to be part of the standard set API or not? It's simply a choice.
But it's not that simple, as you have made plain with your references to history. Such a choice creates a precedent aka principle.
Judging from some of the arguments in other threads, I suspect some people think that ALL the regular methods are only there for legacy reasons,
I tend to agree that they're legacy, but I think it's irrelevant to the discussion. You are correct to focus on whether adding them is likely to cause backward compatibility issues, but I don't think an acceptable degree of backward compatibility is a positive reason to implement something. BTW, thank you for clarifying that you aren't (in these posts) advocating this change. I shouldn't assume that lack of a disclaimer means you're advocating rather than arguing a specific point.
BUT: This *may* be a different case -- the Set ABC (and set
duck-typing) is probably far less used than for Sequences.
I don't know about the Set ABC, but duck-typing is presumably quite common. {1}.union([2]) uses set duck-typing.
no it doesn't -- the set.union method takes any iterable -- that's documented:
[list of documentation references omitted]
no duck-typing here.
What do you think the type "iterable" is? It's not a concrete type. The Iterable ABC is defined to include all classes that provide an __iter__ method (see Lib/_collections_abc.py). In other words, "iterable" is a named duck type. It is defined by "you can use it as X in 'for y in X'" (or equivalently, applying the builtin iter to it returns an iterator). For the purposes of set's named methods, an "iterable" is "sufficiently set-like" to use set operations on it. That's duck typing.
all you need mathematically is the ability to iterate the argument,
which is why it works with any iterable.
That's imprecise. That's why it's *possible* to make it work with any iterable. But Python doesn't always implement things that are possible, and sometimes it implements possible things that turn out to be bad ideas, causing great pain in both the use and the fix (eg, Python 2's union of bytes and str).
The other thing you need mathematically to have a set is the 'in' operation. If mutable, you need an idempotent .add, and .remove.
no one is arguing that the ABC doesn't provide the minimum API for a mathematical set here.
Nor do I claim they did. My point is that the mathematical minimum is far less than what Python provides, and the "practicality" koan applies, so we provided a lot more than the minimum. Do we need to provide near duplicate methods that coerce iterables to set? I don't know, somebody needs to argue the practicalities.
Of course convenience counts. It's not obvious to me whether the convenience of having those methods outweighs the parsimony of only implementing the dunders.
I had to go look up "parsimony" to make sure -- and I still don't know what you're point is. Maybe that's not the word you meant?
"Parsimony" here is just a formal term for "YAGNI, so don't waste time typing it".
In fact, it's not obvious to me whether there's *any* convenience to having those methods. Shouldn't we want to encourage the use of the more concise and less cluttered operators, which also have the advantage that either operand can provide the implementation?
Well: two points:
1) why does the built in set object have them? Maybe it shouldn't, but it does, so there is something to be said fro making other "Sets" in the standard library the same.
There may be something to say *for* doing it, but "we did it over there" is more of a "it's possible" than a reason for.
2) the advantage, maybe small, and made by the OP, is that the methods work on any iterable, rather than only on sets. Is that a big deal? not huge, but it is nice sometimes.
I would tend to go with "Explicit is better than implicit" unless the coercion of iterable to set is frequently useful. Treating the results as abstract collections, where l = [1, 2, 1] and s = {1}, l.extend(s) and s.union(l) are quite different things. The point is not that I think the use of set.union on arbitrary iterables *is* frequently buggy; it's that without frequent use, there's little experience on which to base a judgment. (I'm not making a claim about frequency. I personally have never used those methods on non-sets, YMMV.)
The OP didn't want to make their own, they wanted built in set like objects to behave more like sets (dict views, in particular).
I'm not criticizing the OP. I'm pushing back on the idea, on the usual grounds of "why should all users of Python bear the burden of a slightly larger standard programming environment, and the maintainers the burden of providing and maintaining it?" The status quo wins ties.
But anyway, if we're going to say "derive from it, or construct one." then why have ABCs at all ?!?
Nobody is arguing that "derive from it, or construct the duck type" is *always* the answer. The reason for having ABCs is that names are powerful. You can describe a duck type as "all objects that have __iter__ and __next__", but it's also useful to have the name "Iterator" for the collection of all such objects. Also, many ABCs provide useful generic implementations.
What's the point? You want to add "There should be two-- and preferably exactly two --obvious ways to do it" to the Zen?
tell that to the author of the built in set object -- that decision was made long ago.
Which means that backward compatibility with existing code is important, and therefore those methods weren't removed in Python 3.0, and probably won't be removed. "Although practicality beats purity" overrides any of the other koans in the right situations, and backward compatibility is one of the most important factors. "Practicality" also is the exception that justifies adding new ways to do old behaviors.
Anyway, this is not a big deal to not add -- but it's not a big deal to add, either.
An excellent summary of your position, which I now understand. ;-)