Christopher Barker writes:

 > But again, not worth any more of my time that I have already spent.

Feel free not to read or respond.  (I mean that literally, I don't
want to take up more of your time just because I responded.  I'd be
interested in your response if you care to make one.  I do think that
there are some general principles of software design here, and also
some issues of how they should be applied to the Python language.)

 > if they required something set like, they would require something
 > in set that was not in all iterables.

That's the opposite of duck-typing, though.  Duck-typing is about
*sufficient* conditions for treating a object as an instance of the
*argument's* intended type.  Whether a object is sufficiently set-like
depends on what you're going to do with the object, not on all the
irrelevant attributes that actual sets have.

 > > Do we need to provide near duplicate methods that coerce
 > > iterables to set?

 > I don't think anyone is asking fort that

I think I've failed to convey my meaning, because the whole point is
that the named methods are the same operations as the dunders except
that they also allow general iterables, which is possible by
forgetting that iterables have an order (and then reimposing an
implementation-dependent order) and forgetting that they may contain
duplicate values.  It's the loss of the two latter characteristics
that I mean by "coerce to set".

 > But here's a (n abstract) use case:
 > 
 > def some_fun(a_set, some_args):
 >     ...
 >     a_set.union(something_iterable)
 >     ...

Of course it's easy to construct hypotheticals which fail if people
decide to apply them to views instead of builtin sets.  My question is
whether the convenience of these functions is genuine, or whether it's
an attractive nuisance.  My argument here is like the claim the loose
behavior of builtin zip with respect to unequal-length iterables is an
attractive nuisance.

As I see it, the language design questions are:
(1) "Does consenting adults apply here?"
(2) "Is the convenience that great?"

I had a couple more that have to do with issues of implementing the
non-dunder methods on all classes that derive from Set, but I'm pretty
sure those are solved by providing generic concrete methods in the Set
ABC like

    def union(self, it):
        return self.__or__(set(it))

 > So then I need to either wrap something_Iterable in set(), and use
 > the | operator,

Which is what I would do:

    x.union(y)
    x | set(y)

I agree that ".union(y)" may be easier for many people to type (you
don't have to do a mental gear change to an operator notation which is
different from conventional set theory notation), but as you can see
the number of characters is the same.  I don't see a huge cost to this
as people can get used to the explicit conversion, and for other set
operations the operator versions are shorter.

The counterargument is that as long as builtin set supports the named
versions, people will use them and expect them on all Sets.  Now that
I realize the Set ABC can provide all the non-dunder methods in
reasonably efficient generic implementations, that argument is a lot
stronger than I thought.  But I'm still enough of a curmudgeon to
think it would be a better idea to use explicit conversion and the
operator forms. ;-)  (Don't argue back, I know that's not going to
convince anyone. :-)

 > I guess I don't like the inconsistency between the "prototype" builtin and
 > the ABC -- seems strange to me.

I don't either.  I'm just willing to bear it in the face of "Explicit
is better than implicit" and "In the face of ambiguity, refuse the
temptation to guess" (and for backward compatibility's sake on the
builtin set).  In this case, is someSet.union(someList) what I really
want, or is it someList.extend(someSet)?

If you want to argue "look, .extend also takes any Iterable including
sets that are arbitrarily ordered, I think they're symmetrical", then
I disagree but I'm not going to convince you.[1]

 > And there is nothing in the docs that discourages use of the
 > methods in favor of the operators. In fact, there is a section that
 > describes why the methods are there, and how they can be useful.

Are you referring to

    Note, the non-operator versions of union(), intersection(),
    difference(), and symmetric_difference(), issubset(), and
    issuperset() methods will accept any iterable as an argument. In
    contrast, their operator based counterparts require their
    arguments to be sets. This precludes error-prone constructions
    like set('abc') & 'cbs' in favor of the more readable
    set('abc').intersection('cbs').

I don't see anything there about why they're useful, only that if you
want to intersect with something not a set (which is mathematically
undefined! :-), they're more readable.  And, of course "set('abc') &
set('cbs')" is *shorter*.

The tutorial doesn't mention the non-operator versions at all in the
obvious place (section 5.4).

Footnotes: 
[1]  FWIW, the former destroys information about order and duplicity,
while the latter preserves duplicity while introducing some
arbitrariness into the order, so that IMHO the former is dangerous in
a way the latter isn't.  YMMV.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/4VE24ZQ6ZPI5OZSFRBEPPN65BKFRGR42/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to