Thanks for taking a close look Eric! On 1/26/21 1:23 PM, Eric Traut wrote:
Like Guido, I’m lukewarm on this proposal. It provides some value, but that value seems relatively low and may not be enough to justify the feature.
Here are some additional pieces of feedback.
I don’t understand why TypeForm is a generic type that accepts an optional type argument. I don’t see any reason why `TypeForm` needs to be parameterized. It’s not clear what meaning the type parameter has in this context. Therefore it’s also not clear whether it should be invariant or covariant. It leads to odd questions like “is `TypeForm[int | str]` the same as `TypeForm[int] | TypeForm[str]`”? > The examples in the PEP don’t motivate the need for a generic type either. These examples could all use a bound type variable instead.
```python T = TypeVar("T", bound=TypeForm) def isassignable(value: object, form: T) -> TypeGuard[T]: … def trycast(form: T, value: object) -> Optional[T]: ... ```
Interesting. I was going for the idea that TypeForm[T] applied a constraint to a T that appears in multiple places, where T can only be a TypeVar. (So a construction like `TypeForm[int]` would be rejected.) I actually like `TypeVar("T", bound=TypeForm)` a lot better as a way to propagate constraints to other parts of the signature. So I'll drop the type parameter from TypeForm.
I therefore strongly recommend dropping the type parameter from TypeForm. If you do so, many aspects of this design become simpler. You can eliminate most of the explanations and special rules later in the document (including the sections titled “Type Consistency”, “Overloading”, and “Interactions with Type[C]”).
Nit: In the example under “Using TypeForm Types”, the `meet_types` function signature is invalid because it uses a lone instance of TypeVar `U`. Perhaps you meant to include another input parameter `u: TypeForm[U]`?
Ah. I didn't know a lone TypeVar was improper. So I guess the example then becomes: S = TypeVar('S', bound=TypeForm) T = TypeVar('T', bound=TypeForm) def meet_types(s: S, t: T) \ -> Union[S, T, TypeForm]: ...
As others have pointed out, an assignment expression (walrus operator) cannot be used as a statement. I also think it’s a really bad idea to change the semantics of assignment based on whether `=` or `:=` is used. The semantics should be consistent.
In the first sentence under “Values of type TypeForm”, you say “A particular literal value…”. I was confused by this because you used the term “literal”, but I think you just mean “A value…” regardless of whether it’s a literal expression.
Right, was using the English term "literal". Will rephrase.
You define a new term “inhabit”. AFAIK, this term isn’t used in any other type-related PEPs, so I find it to be confusing and out of place. I’d like to suggest instead using the term “assignable” or “compatible with”. You also use the term “inhabitant” a few sentences later, but it has a slightly different connotation here.
Ah I was using the term "inhabit" from type theory literature. I believe it is equivalent to "assignable" or "compatible with", so I'll go with those instead.
You mention that `NoReturn` is not a valid TypeForm. Why would that be excluded? It is a valid parameter and return type annotation, so it seems odd to exclude it.
My understanding is that NoReturn can only be used as a return type and not as either a parameter type or a local variable type. At least PEP 484 gives no such examples in those positions, and it doesn't make logical sense to me to have a parameter of type NoReturn. I was thinking it might be best to restrict TypeForm to only refer to forms that can legally be used in *all* "typelike" locations. Such a restriction would rule out NoReturn, because you can't use that as a local variable type; Final[...], because that can only be used as a variable type and not as a parameter or return type; and some other forms too.
I don’t agree with the proposed inference rules in the “Type Inference” section. My recommendation is to delete this section entirely. No other type-related PEPs prescribe inference rules, and existing type checkers vary in their behavior. It would be inconsistent to dictate an inference rule in this particular case. In any event, I don’t think a type checker should ever infer type `TypeForm`, especially in the example you provided.
I'm okay with not declaring rules to infer a TypeForm. Users will then be required to explicitly annotate where usage is desired, and I think that's okay.
Today, Pyright infers the type of `A_FORM` as `Type[str] | None` which is a much better (more precise) answer than `TypeForm`. > -- Eric Traut Contributor to Pyright and Pylance Microsoft Corp.
-- David Foster | Seattle, WA, USA Contributor to TypedDict support for mypy