Hi Barry,
Thanks for the note. Apologies for the slow reply — your email got trapped in
Microsoft’s spam filters, and I just noticed it.
The idea of using a wrapper type was my first thought too. In fact, I
implemented that solution in prototype form. It was disliked by almost everyone
who tried to use the feature. The wrapper approach also got a negative reaction
on the typing-sig when I posted the initial proto-spec. A wrapper prevents some
common use cases (e.g. filter functions) and was found to be cumbersome and
confusing.
I understand your concern about the fact that type guards return bools but this
is not reflected in the return type. This was debated at length in the
typing-sig, and we considered various alternatives. In the end, we weren’t able
to come up with anything better. I’m somewhat comfited by the fact that
TypeScript’s formulation of this feature (which was the inspiration for the
idea and is generally a well-liked feature in that language) also does not
directly mention “boolean” in its return type annotation. Here’s an example of
the syntax in TypeScript:
```
function isNone(type: Type): type is NoneType {
return type.category === TypeCategory.None;
}
```
-Eric
On 4/6/21, 1:31 PM, "Barry Warsaw" <[email protected]> wrote:
The Python Steering Council reviewed PEP 647 -- User-Defined Type Guards, and
is happy to accept the PEP for Python 3.10. Congratulations Eric!
We have one concern about the semantics of the PEP however. In a sense, the
PEP subverts the meaning of the return type defined in the signature of the
type guard, to express an attribute of the type guard function. Meaning, type
guard functions actually *do* return bools, but this is not reflected in the
return type:
"Using this new mechanism, the is_str_list function in the above example would
be modified slightly. Its return type would be changed from bool to
TypeGuard[List[str]]. This promises not merely that the return value is
boolean, but that a true indicates the input to the function was of the
specified type.”
In fact, the promise that it returns a bool is de-facto knowledge you must have
when you see “TypeGuard” in the return type. It is an implicit assumption.
Generally this might not be a problem, however when a type guard function is
used for multiple purposes (e.g. a type guard and a “regular” function), then
the return type is misleading, since a TypeGuard object is *not* returned.
It’s unclear what type checkers would do in this case.
The SC debated alternatives, including the decorator syntax specifically
mentioned in the Rejected Ideas. We also discussed making TypeGuard a
“wrapping” type defining an __bool__() so that e.g. is_str_list() would be
defined as such:
def is_str_list(val: List[object]) -> TypeGuard[List[str]]:
"""Determines whether all objects in the list are strings"""
return TypeGuard(all(isinstance(x, str) for x in val))
but this also isn’t quite accurate, and we were concerned that this might be
highly inconvenient in practice. In a sense, the type guard-ness of the
function is an attribute about the function, not about the parameters or return
type, but there is no way to currently express that using Python or type
checking syntax.
I am not sure whether you considered and rejected this option, but if so,
perhaps you could add some language to the Rejected Ideas about it. Ultimately
we couldn’t come up with anything better, so we decided that the PEP as it
stands solves the problem in a practical manner, and that this is for the most
part a wart that users will just have to learn and internalize.
Cheers,
-Barry (on behalf of the Python Steering Council)
_______________________________________________
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/LEXTUSWQOIH7P2XZ3OVXFAIIQC6NWX2E/
Code of Conduct: http://python.org/psf/codeofconduct/