TL;DR: declaration only syntax is a non-starter. Even if we tried to add 
specialised syntax that only appears in annotations, it would become a 
regular Python expression almost immediately.


On Sun, Jan 09, 2022 at 08:42:14AM -0800, Christopher Barker wrote:

> 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?

That is not a valid "either/or" choice. The choice is:

* Python expressions that have multiple meanings (the status quo);

  (e.g. subscripting `obj[x]` already had 4+ meanings before its
  use in typing)

* or Python expressions that have multiple meanings, PLUS new 
  declaration syntax that is only valid in annotations.

And I will argue below that the culture of Python is such that the 
second choice is practically *impossible* without a radical shift in the 
culture.

Let's say that we decide to add specialist declaration-only syntax for 
type-hints. What next?

First, we need a way to distinguish between type-hints that are 
declarations from type-hints that are expressions. Let's say that we use 
the proposed t-string syntax:

    spam: t"declaration goes here"

That tells the interpreter to treat everything inside the quotes as a 
pure declaration, not an expression, with no runtime effect.

I'm going to put aside the question of what syntax is allowed for the 
declarations inside the quotes, because that's actually not that 
important. What happens after we add this declaration syntax?

The first thing that happens is that people interested in runtime 
processing of annotations will want to inspect the declaration, without 
having to scan the source code (which might not be available).

Python has a strong culture of runtime introspection, starting with 
dir() way back in Python 1.x days, so if you think the core devs are 
going to resist the call to make those annotations visible at runtime, 
I think you are remarkably ~~wrong~~ optimistic :-)

That means that the declaration has to have a runtime effect. 
Something has to go into the `__annotations__` dict:

    __annotations__['spam'] = ... # what goes here?

(It doesn't matter precisely what the value that goes into the mapping 
is, it could be a string, or a type object, whatever it is, it is a 
value.)

So our declaration is no longer a declaration, like `global`, it is an 
expression that returns a value. The parser merely restricts its use to 
annotations like `spam: t"declaration"`.

Why can't we use that nifty new declaration syntax in type aliases? I 
mean, it already evaluates to a value that can be inspected at runtime, 
so we just have to relax the restriction on where it can appear so we 
can use it in type aliases as well as directly in annotations:

    T = t"declaration goes here"
    spam: T|None

But if we can do that, then our declaration is just another expression.

It has a value, it can appear outside of annotations. People are going 
to want to treat it as a first-class value (no pun intended), even if 
only for testing purposes:

    # Unit tests
    for T in [t"declaration",
              t"another declaration",
              t"yet another",
              t"my hovercraft is full of eels"]:
        self.assertIsInstance(T, typing.Generic)
        ...

Even if it doesn't happen from day 1, rapidly whatever restrictions on 
where the syntax is allowed will be relaxed, because that's the sort of 
language Python is. Once we make that first (and inevitable!) step to 
give these type declarations an introspectable value, then they will 
become first-class expressions as sure as death and taxes.

So I maintain that *declaration only syntax* is doomed. Whatever syntax 
we invent, there is going to be irresistable pressure to make it a 
first-class expression and not just restrict it to annotations.

And if that is the case, then why do we need the t-string quotes?

That's not a rhetorical question.

Something like t-string quotes, or some other pair of delimiters, *may* 
be useful if we have our hearts set on syntax which is radically 
different from regular Python expressions:

    spam: t"array 1 to 50 of int"  # Hybrid of Pascal and Hyperscript
    eggs: t"{(+⌿⍵)÷≢⍵}"  # I don't even...

Just as we have `[ ... ]` delimiters for list comprehensions. Maybe it 
turns out that there are cases where we need delimiters. But if so, I 
hope they aren't quotation marks (with or without the t-prefix), since 
that will be confusing as far as the existing use of strings as forward 
references.

But why do we want type hints to be so radically different from regular 
Python expressions? How does that make typing easier to read and the 
language less complicated, if we have to learn *two* languages to be 
fluent in Python instead of one?

Outside of that, the t-string delimiters are redundant. There is no need 
to wrap the proposed arrow syntax in quotes, as the PEP makes clear they 
can be handled just fine as an expression. The arrow expression doesn't 
need extra delimiters, it adds nothing. They're just noise.


> > 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.

How is it different? Aside from the syntax requirement that the left 
operand is parenthesized, we can treat it as an operator:

    (one of more input args) arrow operator return-arg

Whether the parser treats it as a binary operator or something 
different, like the dot name.expression, isn't really important. It is a 
symbol that has a left-operand and a right-operand, using infix syntax. 
I call that an operator, at least in informal language.

There's no dunder for the arrow, just like `is`, `is not`, `or`, `and`, 
`not`, so no operator overloading. Just like `is` etc. They are still 
operators.

And just like other operators, if you pass the wrong input types, it 
will raise a TypeError.



-- 
Steve
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@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/2QBNZLRNIKS4Y4HNCSB2XVT6KNTC57IU/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to