Thanks for linking the question and starting the discussion here!
My understanding is that in PEP 484, type aliases were global variables that were assigned to types. Any locals assigned to a type would be treated as a value rather than part of the type hierarchy. The reason behind this is to ensure we have a consistent class
hierarchy when performing type checking across a codebase.
If more precise scoping is allowed, can type aliases be defined inline in a function (like the counter-examples in PEP 613)? Do we care if it’s used before it’s referenced, and if so, does that break assumptions if it’s in scope when it’s
used as an annotation, but out of scope when that annotation needs to be compared to something else? I’d argue that we don’t ever want local variables to be allowable as type aliases to avoid scoping issues changing the type hierarchy at different points.
That said, if the proposal instead is to allow type aliases strictly as toplevel class attributes, that seems doable because class attributes are essentially treated like qualified globally accessible values. However, we will have to explicitly
prohibit type aliases that capture any scoped generics to avoid a situation where constraints need to be solved globally.
For example,
class Foo(Generic[T]):
A: TypeAlias = T
This a huge can of worms, and we lose the simplicity of the assertion (see PEP 484) that “type aliases can be as complex as any type annotation” if we allow aliases nested inside classes. Is it worth it?
Finally, a slightly unrelated part of the discussion:
I’d make the case that the typing PEP should describe a consistent typing experience for the language and that type checkers should hold themselves to follow the system described by the PEP as closely as they can. The idea that type checkers
should be free to do as they wish and PEPs should be more vague to allow for different handling I think makes for a much messier Python typing environment. IMO, we should take into account the opinions of type checker willingness to implement, but in the end
still aim to compromise on a consistent decision across the board.
Anyway, I am curious what others think on whether nested scope type aliases should be allowed and if so, what set of restrictions we need to put on it.
Shannon
From:
Shantanu Jain <hauntsaninja@gmail.com>
Date: Sunday, October 31, 2021 at 12:41 AM
To: None via Typing-sig <typing-sig@python.org>
Subject: [Typing-sig] PEP 613 and type aliases in nested scope
Hello everybody :-)
PEP 613 appears to disallow explicit type aliases in nested scopes:
> With explicit aliases, [...] the inner assignment can either be a valid local variable or a clear error [...]
It also maybe seem to not allow for the possibility of type aliases in nested scope at all:
> [...] because type aliases cannot be defined inside a nested scope
If this was the intention of the PEP, this restriction feels unnecessary to me. Type aliases in nested scope are a valid use case. mypy previously never considered assignments in nested scopes to be type aliases, and we've had multiple
issues concerning this.
Eric mentioned that as a result of this wording, Pyright errors for explicit type aliases in nested scope, but allows implicit type aliases.
I propose we loosen the wording in PEP 613. If type checkers don't wish to add support for type aliases in nested scope that seems fine, but I see no reason to prohibit this via PEP. The following code seems very clear to me in its intention
(as a result of PEP 613!) and type checkers should be free to follow that intention:
```
import typing
T = typing.NewType('T', int)
class C:
V: typing.TypeAlias = T
x: C.V = C.V(5)
```
Conversely, if this proves controversial and we decide we do actually want to prohibit type aliases in nested scopes, we should probably amend PEP 484 to mention this.
Thanks to Nipunn for bringing this up!