[Python-ideas] iterable.__unpack__ method
Alex Stewart
foogod at gmail.com
Mon Feb 25 23:25:03 CET 2013
On Sunday, February 24, 2013 7:43:58 PM UTC-8, Terry Reedy wrote:
> On 2/24/2013 5:07 PM, Alex Stewart wrote:
> > 1. It is a fairly small change to the language
>
> To me, taking something simple and elegant and complexifying it, to
> little benefit I can see other than to solve a problem in the wrong
> place, in no small matter.
I did not say it was a small matter. I said it was a small change to the
language. From a purely practical perspective of what changes would be
required to the language itself in order to support this proposal, in my
opinion, it would not require that much to implement (it would probably
only require a couple of lines of new code and some doc changes), and is
very unlikely to affect any existing code or tools.
(Syntax changes are, in my opinion, far more disruptive changes to the
language: They require a change to the parser as well as the interpreter,
and potentially changes to all manner of other utilities
(debuggers/code-checkers/AST-manipulators/etc) out there in the wild. They
make it much harder to write Python code that supports older Python
releases (with method changes, you can check for the existence of a feature
in the interpreter and selectively use or not use it, but you typically
can't use new syntax constructs in anything that might be run in an older
Python release, because the parser will bomb out instead). They also
require programmers to learn new syntax (if nothing else, to understand
what it means when they come across it in somebody else's code). What's
more, every syntax change potentially limits what can be done with the
syntax in the future (for example, by using up special characters or
constructs so they're not available for other things), and so on.
Personally, I think there should be a much higher bar for syntax changes
than for adding a new special method, not the other way around.)
You also seem to be defining "in the wrong place" as "in a different way
than I personally have a use for".. As I pointed out (which you seem to
have completely skipped over in your reply), there are use cases where the
consumer side is the right (or only) place, and there are other different
use cases where the producer side is the right (or only) place. The two
are not mutually-exclusive, and improving one does not really address the
other issue at all.
I want to emphasize that I am not saying that we shouldn't extend unpacking
notation to support partial-unpacking; in fact I think it might well be a
good idea. What I am saying, however, is that if we do, I do think it's a
much bigger change to the language than what I proposed, and it still
doesn't actually address most of the issues that __unpack__ was intended to
deal with, so it's really not an either-or sort of thing anyway.
Certainly, adding a new special method to
> some category of objects has not effect unless changes are made to the
> interpreter elsewhere to make automatic use of that method. Otherwise,
> you could just define a normal method to be used by user code.
My proposal does not include adding a new special method to any existing
objects. It adds the _ability_ for people to add a special method to
objects *in the future* and have the interpreter take advantage of it. It
therefore should have no effect for any existing code.
> 2. There are (in my opinion) already pretty good parallels with this
> > sort of change that have already been implemented in Python (for
> > example, separating the concept of "iterable" from the concept of
> > "indexable").
>
> The related but distinct concepts of sequential access and random access
> are basic to computation and were *always* distinct in Python.
Oh really? Then how, prior to the development of the iterator protocol,
did one define an object which was accessible sequentially but not randomly
in the Python language? If you couldn't do that, you can't claim that the
concepts were really distinct in Python, in my opinion.
The truth is that the concept of an iterable object vs. an indexable object
may have been distinct *in some people's minds*, but it was *not* originally
distinct in the Python language itself. People decided that that should
change, so the language was extended to make that happen. It should also
be noted that the two concepts were not distinct in *everyone's* minds (I
remember straightening out confusion on this point in numerous people's
understanding (and still need to occasionally), particularly those who did
not come from a classical computer-science background). However, just
because there were some people who didn't see them as distinct did not mean
that it was an invalid way for other people to view them, or that they
shouldn't ultimately be distinct in the language..
With all respect (and I do actually mean that), your primary argument
against it seems to be one of intellectual complacency: "I've never
considered that they might be different, so they shouldn't ever be
separated, because then I don't have to change the way I think about
things".
The addition of __iter__ along with __next__
> added more benefits than __next__ alone would have.
>
You seem to be making my point for me. In essence, __unpack__ is really
just the equivalent for the unpacking operation to what __iter__ is for
"for" loops. Is it strictly required in order to support the basic
behavior? No (you could do for loops over simple iterables with just a
variant of __next__, if you really wanted to), but it allows some more
sophisticated objects to provide more useful behaviors by giving them more
context about how they are being invoked (in the case of __iter__, by
telling them ahead of time that they are going to be used in an iteration
context, and allowing them to create or alter the initial object that the
for loop interacts with). This provides "more benefits than __next__ alone
would have", so it was added to the language.
Logically, by the same argument, and in almost exactly the same way,
__unpack__ provides more benefits than __iter__ alone would have (by
telling them that they are going to be used in a particular unpacking
context, and allowing them to alter the object used for that type of
iteration), and therefore should arguably be part of the language as well.
> 3. It is consistent with the general idea in Python that an object can
> > choose to emulate whichever behaviors of other objects make sense,
> > and not emulate other ones that do not make sense. In my opinion,
> > "iterating", and "unpacking" are two related-but-not-the-same
> > language concepts, which currently are unnecessarily entangled.
>
> I do not see that at all. As near as I can tell, both mean 'sequential
> access'.
Not true. Iteration means "sequential access". Unpacking means
"sequential access with inherent length constraints", which is the bit you
seem to be ignoring. The most notable consequence of this (but definitely
not the only one) is that a for loop (for example) will never raise
ValueError, but the unpacking operation will, if it gets what it considers
"wrong" results back from the unpacked object. In this way the two
operations do not interpret the data that the object in question provides
in the same way, and it does not really have the same meaning.
Yes, from a purely mechanical perspective, they perform similar operations,
but programming interfaces are not solely defined by mechanics. The
difference here is one of implied contracts. In simple iteration, there is
explicitly no minimum or maximum number of values that the iterable is
required to produce, and in fact the entire protocol is based on the
assumed perspective that returning a value is always the "success"
condition and not being able to return one is the "failure" case, and in
that context it makes sense to design iterators so that they should always
return more data if they're able to do so. In unpacking, however, when it
gets to the end of the variable list, the conditions are reversed, and
actually returning a value becomes a failure condition. This change of
meaning, however, is not communicated in any way to the iterator (this is
just one example: there are similar contract issues inherent in extended
unpacking as well). This is, in my opinion, a flaw in the interface,
because the language is misrepresenting (bounded) unpacking as (unbounded)
iteration when calling the iterable object.
I admit I do not understand your __unpack__ proposal, since it seemed
> vague and incomplete to me. But until I see your conceptual distinction,
> the details do not matter to me.
>
I'm not exactly sure why you consider it vague or incomplete. I provided a
specific description of exactly what changes to the language I was
proposing, with method signatures, a description of the new interpreter
behavior and examples of data values in typical scenarios, and accompanied
it with a list of several different use-cases which I believed it would
provide significant utility. I'm not really sure how I could have gotten
more specific without providing a diff against the CPython sources (which
seems a bit much for an initial proposal)..
> 4. It would help significantly with several types of problems that do
> > not currently have great solutions.
>
> I obviously do not see the same pile of problems that would justify a
> new special method.
Obviously, although I'm not really sure why not because I did explicitly
state a bunch of them in my original post. You seem to have just ignored
all of them except for the issue of partial unpacking, which frankly was
not even the most important or interesting use case I presented, in my
opinion. I would recommend you might want to go back and read the last
part of my initial post where I presented several potential use cases for
all this.
I do get the distinct impression, however, that you've already made up your
mind and, right or wrong, there's nothing I could possibly say which would
ever change it, so at this point I'm not sure whether it really matters
(sigh)...
> no way to query an iterator to find out if it has more data available
See how in my separate post:
> "Add lookahead iterator (peeker) to itertools"
I'm not necessarily opposed to that proposal, but I should point out that
it does not actually address the problem I mentioned in this thread at all,
so it's really kinda irrelevant to that discussion.
(Even if that is added to itertools, unpacking still won't use it, nor does
it provide any way to safely query iterables which produce side-effects,
even if there might be a way for them to provide that info without the
side-effects, nor does it provide a way to test for end conditions without
changing the underlying iterable (which might be used elsewhere in scopes
outside the lookahead-wrapper), etc..)
--Alex
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20130225/b6de1651/attachment.html>
More information about the Python-ideas
mailing list