Perhaps it's worth remembering that this thread spun off one about adding syntax to Python because the current syntax isn't capable of easily expressing an important type hinting concept (i.e. Callable). So arguing that Python is completely readable for type hints is a bit off-mark, isn't it?

The question at hand is whether changes in syntax that are desirable for type hinting should be applied across the board in all of Python.

I think the debate boils down to:

Is it more clear for readers to have two different (but related) related syntaxes for two different (but related) purposes, or to have one Sytax that is used in different ways? 

Chris A addresses this specifically:

> To that extent, I definitely want to keep annotation syntax and Python syntax the
same; if there's a new feature needed for annotations, add it to the
base language, even without any useful semantics.

And here's where reasonable people can disagree :-)

> (Valid syntax without semantics is what we have with the matmul
operator. I can syntactically parse "f@g(y)" because I know how the
matmul operator works, even without knowing the data types involved.

Sure: because it's a binary operator like all the other binary operators.

> If "x->y" is syntactically valid anywhere in Python code, it's not a
problem that there are no core data types for which it's meaningful.)

Here's where I'm not so sure -- this looks a lot like a binary operator, but it behaves quite differently. IIUC it would always create a Callable, regardless of what the types were of the two other types. And it would not invoke a dinder on either, yes.

Nor would it be like assignment.

This is even worse than the use of [] in type hinting which is also using the same sytax for a very different meaning -- at least that one is stil calling __getitem__ :-)

-CHB


On Sat, Jan 8, 2022 at 8:46 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Sat, Jan 08, 2022 at 06:30:53PM -0800, Ethan Furman wrote:
> On 1/8/22 5:46 PM, Steven D'Aprano wrote:
>
> > [...] if you hate type annotations because they are unreadable, then you
> > hate Python because Python is unreadable.
>
> Not so.

Are you disputing that annotations use the same syntax as other Python
expressions? If not, I don't see how you can deny that "type annotations
are unreadable" implies "Python expressions are unreadable", which in
turn implies "Python is unreadable".


> A simple list comprehension is (usually) quite readable, while a
> triply-nested list comprehension all on one line is not.

Indeed. We can abuse any syntax. So do we conclude that comprehensions
are "unreadable" because we can write obfuscated triply-nested list
comprehensions?


> Similarly, adding type information in between a variable name and its value
> is not (for me, and apparently others too) readable.

I think that "unreadable" or "not readable" is a complaint that gets
overused, often for the most trivial cases, to the point that it loses
all credibility. Especially when it comes from people who are fluent in
C (which may not be you, Ethan).

http://unixwiz.net/techtips/reading-cdecl.html

"Easily learned", huh. I think that this is one of the clearest examples
of the curse of knowledge as it applies to programming that one could
hope to find.

Anyway, let's compare:

    # C
    int n = 44;

    # Pascal
    var
      n: integer;
    n := 44;

    # Typescript
    var n: number = 44;

    # Java
    int n = 44;

    # Python
    n: int = 44


There are millions who find the C, Pascal, TypeScript and Java perfectly
readable. I don't find it credible that people are incapable of
reading the last one.

Aside: such a type hint is redundant, as mypy is perfectly capable of
inferring that n = 44 makes n an int. Style guides should recommend
against such redundancy, and I would certainly flag that in a code
review. A better example of a *useful* type hint would be:

    L: list[str] = []



> Most horribly of all, cluttering a function header with type information is
> most unreadable.

I hear you. Adding redundant or unnecessary type hints to parameters
just for the sake of having type hints is just clutter, especially if
they are never tested by actually running a type checker over the file.

(Untested code is broken code. If not right now, it soon will be.)

Fortunately, we have *gradual typing*, and nobody should be forced to
use type hints in their projects if they don't want them. Just as we
don't make linters mandatory, we don't make typing mandatory either.

I think that, outside of very simple functions, once we make the
decision to annotate a function, we should space them out:

    # Better
    def func(spam: list[str],
             eggs: float,
             cheese: str = 'cheddar',
             aardvark: str|bytes = "",
             eels: Optional[Tuple[int, str]] = None
             ) -> Hovercraft:


which makes them much easier to read.

Trying to cram them all into one line is abuse of the syntax every bit
as bad as cramming a triply-nested list comp into one line:


    # Worse
    def func(spam: list[str], eggs: float, cheese: str = 'cheddar', aardvark: str|bytes = "", eels: Optional[Tuple[int, str]] = None) -> Hovercraft:


I can read it, I just don't want to. It is too much like hard work
compared to the previous layout.

Even if you don't run a type-checker, those annotations can make useful
documentation. (At least *sometimes*.) If the parameter name doesn't
make it clear what types are allowed, then the annotation can make it
clear. So if you don't use a static checker, you can think of type
annotations as introspectable documentation.


> I started using Python at 2.5.  It was simple, clean, and elegant.

And I started using Python at 1.5, when the syntax was even simpler and
cleaner. And to this day I will never forget the first time I read
Python code, after being told repeatedly how easy to read it, and I
couldn't make head or tails of it. All those colons and square brackets,
it might as well have been APL. (Not that I knew what APL was back
then.)

I knew what a for-loop was, from Pascal, Hypertalk and HP RPN
calculators:

    # Pascal
    for i := 0 to 10 do
      begin
        block;
      end;

    # Hypertalk
    repeat with i = 0 to 10
      block
    end repeat

    # HP-48 RPN language
    0 10 FOR I block NEXT

but I kept seeing loops like this in Python:

    for i in range(11):

or worse:

    for somename in [stuff, thing, another_thing, widget]:

and worse of all:

    for somename in values[1:-1]:

Python for loops looked nothing like any for loop I had seen before, and
they freaked me out, and at the time (early 1990s) there was no publicly
available internet where I could look anything up or ask for help.

And then there were the brackets. Why does Python sometimes use round
brackets, sometimes curly brackets, and sometimes square brackets? x[a]
versus x(a)? Why were there sometimes colons inside square brackets and
curly brackets {a:b} but never inside round brackets? What was the
difference between [1, 2, 3] and (1, 2, 3)?

The whole thing was intimidating, and I just put Python away for about a
year and didn't look at it again until I had bought Mark Lutz' "Python
Pocket Reference" which helped me make sense of it all. That and his
"Learning Python". And never looked back. (Since then, I've often felt
that Python has spoiled me from learning other languages.

The point I am making here is not that I was a dimwit who couldn't even
read Python, but that "easy to read" and "readable" is more a matter of
familiarity than an inherent property of the language itself. With
enough familiarity, even APL is easy to read.


> If I
> had stumbled on it at 3.16 with samples, tutorials, and books all infused
> with typing clutter (which *looks* like boiler-plate even if it isn't) I
> wouldn't have given it a second glance.

And again, I hear you. I too wish people would tone down their
enthusiasm for adding typing to examples that don't need type hints.

We should remember that type hints are a feature aimed at large code
bases, where static typing really is valuable. For three line example
functions, not so much, not even as documentation.


--
Steve
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/35G7WXSHOB3G7GPNLIVWXZ27RZZC2VRM/
Code of Conduct: http://python.org/psf/codeofconduct/


--
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython