Hi,

First of all, sorry for not commenting on this earlier.
I only became aware of this PEP yesterday.


I like the general idea of adding a marker to show that a boolean function narrows the type of one (or more?) of its arguments.
However, the suggested approach seems clunky and impairs readability.

It impairs readability, because it muddles the return type.
The function in the example returns a bool.
The annotation is also misleading as the annotation is on the return type, not on the parameter that is narrowed.

At a glance, most programmers should be able to work out what

def is_str_list(val: List[object]) -> bool:

returns.

But,

def is_str_list(val: List[object]) -> TypeGuard[List[str]]:

is likely to confuse and require careful reading.
Type hints are for humans as well as type checkers.



Technical review.
-----------------

For an annotation of this kind to be useful to a checker, that checker must perform both flow-sensitive and call-graph analysis. Therefore it is theoretically possible to remove the annotation altogether, using the following approach:

1. Scan the code looking for functions that return boolean and potentially narrow the type of their arguments.
2. Inline those functions in the analysis
3. Rely on pre-existing flow-senstive analysis to determine the correct types.

However, explicit is better and implicit. So some sort of annotation seems sensible.

I would contend that the minimal:

@narrows
def is_str_list(val: List[object]) -> bool:

is sufficient for a checker, as the checker can inline anything marked @narrows.
Plus, it does not mislead the reader by mangling the return type.


An alternative, and more explicit, approach would be to use variable annotations.
So:

def is_str_list(val: List[object]) -> bool:
    """Determines whether all objects in the list are strings"""
    return all(isinstance(x, str) for x in val)

might become:


def is_str_list(val: List[object]) -> bool:
    """Determines whether all objects in the list are strings"""
    val: NarrowsTo[List[str]]
    return all(isinstance(x, str) for x in val)

Although the above lacks flow control and is thus ambiguous without the convention that `NarrowsTo` only applies if the result is True.


An alternative formulation would require the annotation to dominate the function exit:

def is_str_list(val: List[object]) -> bool:
    """Determines whether all objects in the list are strings"""
    if all(isinstance(x, str) for x in val):
        val: NarrowsTo[List[str]]
        return True
    return False

This is unambiguous.


Finally, I would ask for a change of name.

The "Type" part is redundant, since it is a type annotation, and the "Guard" part is incorrect. It is only a guard when used, the function itself is a predicate that narrows the type of an argument. "Narrows" or "NarrowsTo" would be better.


Cheers,
Mark.


On 09/02/2021 4:21 pm, Guido van Rossum wrote:
I think we have reached consensus on PEP 647 in typing-sig. We have implementations for mypy and pyright, not sure about the rest. This PEP does not affect CPython directly except for the addition of one special item (TypeGuard) to typing.py -- it would be nice to get that in the 3.10 stdlib.

I'm CC'ing python-dev here to see if there are any further comments; if not, we can initiate the approval process by creating an issue at https://github.com/python/steering-council.

--
--Guido van Rossum (python.org/~guido <http://python.org/~guido>)
/Pronouns: he/him //(why is my pronoun here?)/ <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>

_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/NOLCFYLYAQQHXISNMPYCEOAZ7ZPFCGUW/
Code of Conduct: http://python.org/psf/codeofconduct/

_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/4LKI6IGCT7JHH5C3YQPA4SXHDQWJC5Q2/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to