Hi Shannon,
Sorry that it's so quiet here. The mypy team members have been
alternatingly super busy with Dropbox stuff and on vacation (I'm just back
and in a week I'm going again for another week; Ivan is on vacation until
the end of next week; Jukka is on vacation intermittently for the next few
weeks).
That said I'd like to provide some feedback on your proposal.
First, the `z: Any` situation looks like a bug or accidental feature to me.
This is definitely meant (and works) as a variable declaration; that it
also allows using `z` as a type seems wrong. I can't find any evidence in
PEP 484 that this was intended; in mypy it's likely the accidental result
of other design choices meant to shut up errors about `Any`.
Next, it would be good to be clear about the reason why you want type
aliases to be explicitly marked as such. I *think* that it is so that a
type checker can know whether something is a type alias even if it hasn't
seen the definition of the type to which it is aliased, right? And this
would be handy for parallelization of checking large collections of files.
I think I might have head you explain this in person before, but I'm not
sure if I can do the argument justice. For my own edification here's some
thinking aloud about this.
- For simple aliases involving builtin types I don't think this is an
issue. E.g. if a type checker encounters `T = int` it should have no
problem knowing that `int` is a type and hence T is, too. Ditto for types
defined in `typing` such as `List` or `Mapping`.
- If the type is defined explicitly earlier in the file it also shouldn't
be an issue. E.g. if a type checker sees `class C: ...` and then later in
the same file `T = C` (or `T = C[xxx]` if C is generic) it should be
totally clear that T is a type.
- So it looks like this really is only an issue when we have two modules,
m1 and m2, where in m1 we define `class C: ...`, and in m2 we have `from m1
import C` followed by `T = C` or `T = C[<something>]`. At this point we
don't know whether T is a type or not until we have processed m1 to the
point where we know that C is a class. Under your new proposal we'll know
that T is a type (alias) as soon as we read `T = TypeAlias[<whatever>]` in
m2, regardless of whether we have processed any of its imports.
- I guess there's an additional issue when the type checker cannot find the
source code for module m1 -- in this case we will eventually come to the
conclusion that C has type `Any`, and then T also has type `Any`. (Maybe
this is the reason for the `z: Any` corner case -- we can't exclude the
possibility that C is a type, hence we can't exclude that T is a type, but
if it is, it must be `Any`.) But this seems a corner case and I doubt that
it is part of your motivation.
- Now an open question (for me) is why it is important that we know whether
T is a type or not. If the checker sees a use of a variable X in a type
context (e.g. in an annotation or cast) it might as well assume that X is a
type for the time being -- an error can come later once the definition of X
is clearer. (Even if it is known that X is a type, there could still be
errors, e.g. it could be a non-generic type in a generic position.)
- And doesn't the same reasoning apply to simply importing a class? If we
see `from m1 import C` we don't know whether C is a type until we've
processed m1 to the point where it's clear that C is a class (or a type
alias). For a few seconds I thought it was about chains of imports, where
`from m1 import T` might need to process m1 to see a type alias definiton
of T, which might in turn depend on something that m1 imports from
elsewhere, but that same reasoning would apply to chains of imports passing
a class definition along.
- So I'm still stumped -- what is special about type aliases?
Finally I fear that type aliases are so pervasive that changing all of them
to the explicit notation in any significant code base is going to be
prohibitive -- even if you had a perfect tool to find type aliases (e.g.
some custom code in mypy or Pyre) this would create a gigantic diff,
causing large numbers of merge conflicts, blame noise, and some misfires
that could cause hours of debugging or even production failures.
Last and (for now) least, I can't recall if there is a good reason to
prefer `x: TypeAlias = int` over `x = TypeAlias[int]` (or even `x:
TypeAlias[int]`?).
If you only have a little time for a response, please focus on answering
the question "what problem is this solving", since knowing the problem may
cause some creative minds to produce alternative solutions (or at least
help us estimate the magnitude of the issue and perhaps provide preferences
for one syntax or another).
--Guido
On Thu, Jul 18, 2019 at 2:10 PM Shannon Zhu
Hi everyone,
I’d like to continue the discussion from our last typing summit on explicit type aliases. A quick summary of the current state and the proposal --
*Current state:*
```
from typing import List
x = List[int] # considered a type alias
y : Type[List[int]] = List[int] # considered an expression
z : Any # considered a type alias
z : x = [] # fine
z : y = [] # invalid type error
```
*Proposal (with explicit aliases):*
```
from typing import List, TypeAlias
x = TypeAlias[List[int]] # considered a type alias
y = List[int] # considered an expression
z : Any # considered an expression
z = TypeAlias[Any] # considered a type alias
reveal_type(x) # Type[List[int]]
reveal_type(y) # Any (return type of __getitem__)
z : x = [] # fine
z : y = [] # invalid type error
```
Some of the benefits we’re hoping to gain from explicit type aliases:
- Clearly distinguish between an unannotated global assignment and a type alias, especially when parsing forward-referencing string annotations. - Avoid the confusing case of type aliases in which some part of the type is invalid or undefined. This would facilitate warnings on invalid types at the alias definition rather than later on when the alias is used. - Make valid and invalid types more intuitive to Python programmers by shifting from delineation of non-aliases with a meta annotation toward delineation of aliases with `TypeAlias`. - Remove special treatment of values annotated as `Any`, which currently break all type aliasing rules. This will also allow us to clean up some of the distinctions we maintain between unannotated values and explicit Anys.
Note: We also considered denoting the alias as an annotation (e.g. `x: TypeAlias = int`) as an alternative to the syntax above.
I’m interested to hear your thoughts and suggestions on making type aliasing explicit going forward – we’d like to start implementing a version of this in Pyre soon!
Shannon _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him/his **(why is my pronoun here?)* http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...