Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document we're not tracking relationships between symbols #16018

Merged

Conversation

ikonst
Copy link
Contributor

@ikonst ikonst commented Sep 2, 2023

Fixes #15653.

I did not use @erictraut's "quantum entanglement" metaphor, though I find it to be quite illustrative :)

- :py:func:`issubclass` like in :code:`issubclass(cls, MyClass)` will narrow ``cls`` to be ``Type[MyClass]``
- :py:class:`type` like in :code:`type(obj) is int` will narrow ``obj`` to have ``int`` type
- :py:func:`callable` like in :code:`callable(obj)` will narrow object to callable type
- :code:`obj is not None` will narrow object to its :ref:`non-optional form <strict_optional>`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strangely we didn't mention this

Comment on lines 88 to 89
Limitations of narrowing
~~~~~~~~~~~~~~~~~~~~~~~~
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hope this is the right place. I wanted it to have a heading, to make it easy to refer people, but it's also a bit strange that it comes as a topic in the same hierarchy and right before "is_subclass" and "callable".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make it a heading and move it to the bottom of the page.

Copy link
Collaborator

@hauntsaninja hauntsaninja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for writing this up!

Comment on lines 88 to 89
Limitations of narrowing
~~~~~~~~~~~~~~~~~~~~~~~~
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make it a heading and move it to the bottom of the page.

return 'spam'

Tracking these sort of cross-variable conditions in a type checker would add significant complexity
and performance overhead and would be computationally infeasible in all but the most basic cases.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
and performance overhead and would be computationally infeasible in all but the most basic cases.
and performance overhead.

Claim feels a little too strong, first half of the sentence says enough.

Tracking these sort of cross-variable conditions in a type checker would add significant complexity
and performance overhead and would be computationally infeasible in all but the most basic cases.

You may override the type checker with a :ref:`cast <casts>`, or rewrite the function to be
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You may override the type checker with a :ref:`cast <casts>`, or rewrite the function to be
You may override the type checker with an ``assert`` or :ref:`cast <casts>`, or rewrite the function to be

When I run into this, assert is usually more ergonomic. It's also safer than cast.

Copy link
Contributor Author

@ikonst ikonst Sep 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably would phrase as "help the type checker with an assert", but I'm not sure it'll be more ergonomic in this case. Maybe I'm tired and missing something obvious?

cast:

def f(a: str | None, b: str | None) -> str:
    if a is not None or b is not None:
        return a or cast(str, b)
    return 'spam'

assert:

def f(a: str | None, b: str | None) -> str:
    if a is not None or b is not None:
        if a:
            return a
        assert b is not None
        return b
    return 'spam'

third option:

def f(a: str | None, b: str | None) -> str:
    if a is not None or b is not None:
        return a or b or 'impossible'
    return 'spam'

Copy link
Collaborator

@hauntsaninja hauntsaninja Sep 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, not more ergonomic in this case, but better in the cases where I usually run into this. But maybe I dislike cast more than most people :-)

I'd do assert a or b; return a or b

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert a or b doesn't help you either because we don't narrow conditionally. (Also, in this case you'd get more than you'd bargain for, as empty b would assert.)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh oops, I guess you'd have to do ret = a or b; assert ret is not None; return ret

@hauntsaninja hauntsaninja merged commit cc8a4b5 into python:master Sep 2, 2023
@ikonst ikonst deleted the 09-01-docs_document_lack_of_entanglement branch September 2, 2023 23:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

type_narrowing.rst: document lack of "second degree" analysis
2 participants