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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/2QBNZLRNIKS4Y4HNCSB2XVT6KNTC57IU/
Code of Conduct: http://python.org/psf/codeofconduct/