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

Should empty intersection be simplified? #20

Closed
NeilGirdhar opened this issue Aug 4, 2023 · 9 comments
Closed

Should empty intersection be simplified? #20

NeilGirdhar opened this issue Aug 4, 2023 · 9 comments

Comments

@NeilGirdhar
Copy link
Collaborator

@randolf-scholz requests this here: #10 (comment)

If so, it should be added to the reductions.

@NeilGirdhar
Copy link
Collaborator Author

Linking @kmillikin's prescient comment.

@mniip
Copy link

mniip commented Aug 4, 2023

Most people seemed to agree that if it should reduce then it should reduce to object or an empty Protocol, which is the opposite of Never.

@NeilGirdhar
Copy link
Collaborator Author

NeilGirdhar commented Aug 4, 2023

Yes, object seems reasonable to me. Whatever we think it is, this issue is more about whether that reduction should be mandated or not.

@NeilGirdhar NeilGirdhar changed the title Should empty intersection be reduced to Never? Should empty intersection be reduced? Aug 4, 2023
@NeilGirdhar NeilGirdhar changed the title Should empty intersection be reduced? Should empty intersection be simplified? Aug 4, 2023
@randolf-scholz
Copy link

It's either object, or one could consider creating a typing.Top which would be an empty Protocol.
The latter might be advantageous, because which Top would match everything just like object, type[object] does not match Protocol.

This makes a difference, for instance in the merge_protocols function I presented:

from typing import TypeVarTuple, Intersection

protocols = TypeVarTuple("protocols")   
# technically we want TypeVarTuple("protocols", bound=type[Protocol])
# but bounds are not supported yet for TypeVarTuple.

def merge_protocols(*protos: *protocols) -> Intersection[*Protocols]: ...
    """Creates the intersection of pairwise disjoint protocol classes."""
    # if intersection is empty, returns a protocol that matches with any class.
    # Note: https://peps.python.org/pep-0646/#args-as-a-type-variable-tuple

Here, one would expect that this function can be chained with itself. But, for instance, consider what happens in the case of merge_protocols(merge_protocols()): If merge_protocols() returns object, then this would raise a type-error, since type[object] is not a subtype of type[Protocol].

This shows that it makes a difference whether object or an empty Protocol is identified with Intersection[()].

@mikeshardmind
Copy link
Collaborator

mikeshardmind commented Aug 4, 2023

I would rather not treat empty intersections as object/any/typing.Top and just use the existing subtype rules "is it a subtype of all of these"? if it is empty, yes. The pragmatism of this is shown with TypeVarTuples. No special case or reduction needed here.

I would not reduce to Any turning a static type into a gradual type, and if we go with object, protocols don't match (being equivalent or a subtype of) (but is that a bug?), so if we do reduce, I think the best option then is to have Intersection to an empty protocol, this relation with object does work.

@randolf-scholz
Copy link

randolf-scholz commented Aug 4, 2023

Just noticed an issue with this whole example, which is that currently PEP544 makes it impossible to type hint functions that return actual Protocol classes, since "Variables and parameters annotated with Type[Proto] accept only concrete (non-protocol) subtypes of Proto." python/typing#1441 mypy complains if one tries to do something like

from typing import Protocol

def top() -> type[Protocol]:  # error: Variable "typing.Protocol" is not valid as a type
    class Top(Protocol):
        pass
    return Top

@mikeshardmind
Copy link
Collaborator

Another reason to just leave empty intersection as empty intersection then

@NeilGirdhar
Copy link
Collaborator Author

@randolf-scholz Can we close this as not added to the specification?

@randolf-scholz
Copy link

Sure.

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

No branches or pull requests

4 participants