On May 14, 2020, at 03:35, Steven D'Aprano <st...@pearwood.info> wrote:
> 
> On Sun, May 10, 2020 at 09:36:14PM -0700, Andrew Barnert via Python-ideas 
> wrote:
> 
> 
>>> for i in itertools.seq_view(a_list)[::2]:
>>>    ...
>>> 
>>> I still think I prefer this though:
>>> 
>>> for i in a_list.view[::2]:
>>>    ...
> 
>> Agreed. A property on sequences would be best,
> 
> Why?

Because the whole point of this is for something to apply slicing syntax to. 
And compare:

    lst.view[10:20]
    view(lst)[10:20]
    vjew(lst, 10, 20)

The last one is clearly the worst, because it doesn’t let you use slicing 
syntax.

The others are both OK, but the first seems the most readable. I’ll give more 
detailed reasons below. (There may be reasons why it can’t or shouldn’t be 
done, which is why I ranked all of the options in order rather than just 
insisting that we must have the first one or I hate his whole idea.)

> This leads to the same problem that len() solves by being a function, 
> not a method on list and tuple and str and bytes and dict and deque and 
> .... Making views a method or property means that every sequence type 
> needs to implement it's own method, or inherit from the same base class, 

But len doesn’t solve that problem at all, and isn’t meant to. It just means 
that every sequence type has to implement __len__ instead of every sequence 
type having to implement len.

Protocols often provide some added functionality. iter() doesn’t just call 
__iter__, it can also fall back to old-style sequence methods, and it has the 
2-arg form. Similarly, str() falls back to __repr__, and has other parameter 
forms, and doubles as the constructor for the string type. And next() even 
changed from being a normal method to a protocol and function, breaking 
backward compatibility, specifically to make it easier to do the 2-arg form.

But len() isn’t like that. There is no fallback, no added behavior, nothing. It 
doesn’t add anything. So why do we have it? Guido’s argument is in the FAQ. It 
starts off with “For some operations, prefix notation just reads better than 
postfix”. He then backs up the general principle that this is sometimes true by 
appeal to math. And then he explains the reasons this is one of those 
operations by arguing that “len”’is the most important piece of information 
here so it belongs first.

It’s the same principle here, but the specific answer is different. View-ness 
is not more important than the sequence and the slicing, so it doesn’t call out 
to be fronted. In fact, view-ness is (at least in the user’s mind) strongly 
tied to the slicing, so it calls out to be near the slice.

And it’s not like this is some unprecedented thing. Most of the collection 
types, and corresponding ABCs, have regular methods as well as protocol 
dunders. Is anyone ever confused by having to write xs.index(x) instead of 
index(xs, x)? I don’t think so. In fact, I think the latter would be _more_ 
confusing, because “index” has so many different meanings that “list.index” is 
useful to nail it down. (Notice that we already _have_ a dunder named 
__index__, and it does something totally different…) And the same is true for 
“view”. In fact, everything in your argument is so generic that it acts as an 
argument against not just .index() but against any public methods or attributes 
on anything. Obviously you didn’t intend it that way, but once you actually 
target it so that it argues against .len() but not .index(), I don’t think 
there’s any argument against .view left.

> and that's why in the Java world nobody agrees what method to call to 
> get the length of an object.

Nobody can agree on what function to call in C or PHP even though they’re 
functions rather than methods in those languages.

Everyone can agree on what method to use in C++ and Smalltalk even though 
they’re methods in those languages, just like Java. (In fact, C++ even loosely 
enforces consistency the same way Python loosely does, except at compile time 
instead of run time—if your class doesn’t have a size() method, it doesn’t duck 
type as a collection and therefore can’t be used in templates that want a 
collection.)

Or just look at Python: nobody is confused about how to spell the .index method 
even though it’s a method.

So the problem in Java has nothing to do with methods. (We don’t have to get 
into what’s wrong with Java here; it’s not relevant.)

> So if we are to have a generic view proxy object, as opposed to the very 
> much non-generic dict views, then it ought to be a callable function 

We don’t actually _know_ how generic it can/should be yet. That’s something 
we’ve been discussing in this thread. It might well be a 
quality-of-implementation issue that has different best answers in different 
Pythons. Or it might not. It’s not obvious. Which implies that whatever the 
answer is, it’s not something that people should have to grasp it to understand 
the feature.

You wouldn’t want to users to base their understanding of iter on knowing 
whether there’s one generic sequence iterator type or one for each type 
(especially since neither is true in CPython, but something halfway between and 
more complicated). And I think the same is true here. So you’re arguing for a 
callable function because it strongly implies a generic implementation, but I 
see that as an argument _against_ a function, not for it, and I also don’t 
think the argument holds anyway because it doesn’t imply any such thing for 
iter.

_______________________________________________
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/RUR25QPBCANNSH2V7JHMX2EW7LBWLWHS/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to