Skip to main content

No project description provided

Project description

type-intersections

A naive prototype of type intersections implementation.


Test Coverage PyPI Supported Python versions

Installation

pip install type-intersections

Intro

Type intersections are a way for a programmer to say that some variable is of type A and type B at the same time which is only possible if it inherits from A and B or if A and B are both structural types with overloaded subclass checks such as Sized or Hashable.

Current issues

Ordering checks

The current implementation assumes that intersections are unordered which makes some sense for two reasons:

  1. I have not been able to come up with an algorithm that can intuitively do structural and ordered intersection issubclass checks at the same time (see the XFAIL testcase). Not sure if that is even possible but I haven't tried for long.
  2. TypeScript doesn't even try to handle order in intersections

The issue arises when we try to decide what to use in issubclass checks: the class itself or its mro().

Let's say that a class C inherits method foo() that is defined in both its parents: A and B. Let's also say that C defines the method __len__ that its parents do not have. If we have an intersection A & B & Sized, what algorithm would we use to check that C uses the correct foo() and that it is Sized?

class A:
    def foo(self, a):
        print(a)

class B:
    def foo(self, a, b):
        print(a, b)

class C(A, B):
    # Makes C Sized
    def __len__(self):
        return 83
  1. If we try to just check issubclass(C, A) and issubclass(C, B) and issubclass(C, Sized), then we are omitting order information and cannot definitively tell that C will inherit foo() from A.

  2. An alternative would be to go through C's MRO in order: checking that each next item in the MRO is a subclass of each argument in the intersection like so:

def __subclasscheck__(self, cls):
    args = self.__args__

    for type_ in cls.mro():
        while args:
            if issubclass(type_, args[0]):
                args.pop(0)
            else:
                break
    return not args

But we quickly realize that the first item in MRO is the class itself which is definitely an instance of A, B, and Sized, thus keeping our check unordered. The naive way to resolve this would be to remove the class itself from its MRO before we start checking:

def __subclasscheck__(self, cls):
    args = self.__args__[1:]

    for type_ in cls.mro():
        while args:
            if issubclass(type_, args[0]):
                args.pop(0)
            else:
                break
    return not args

But now issubclass(C, Intersection[A, B, Sized]) is False because __len__ is defined on C which we skip in the MRO checks.

Another option would be to use both algorithms: unordered algorithm for structural checks and ordered algorithm for inheritance-based checks. But we cannot distinguish between the checks because classes can have their __subclasscheck__ redefined in all sorts of complex ways and because even some structural checks care about order: such as in the example I gave above from TypeScript.

In other words, we can't check that some class C inherits from classes A and B in this specific order (i.e. not from B and A) and check that it implements Sized at the same time. The only solution I see is to abandon either structural checks or order in inheritance checks. Order seems a lot less necessary and fundamental so I decided to abandon it for now for my naive implementation.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

type_intersections-0.1.1.tar.gz (5.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

type_intersections-0.1.1-py3-none-any.whl (5.1 kB view details)

Uploaded Python 3

File details

Details for the file type_intersections-0.1.1.tar.gz.

File metadata

  • Download URL: type_intersections-0.1.1.tar.gz
  • Upload date:
  • Size: 5.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.2.2 CPython/3.10.9 Linux/6.0.19-4-MANJARO

File hashes

Hashes for type_intersections-0.1.1.tar.gz
Algorithm Hash digest
SHA256 1d18e4ec54b18013269642041c32d8bb38e342d5dfa67df5d7efdcfdb3462b75
MD5 d2cc384cc13b9a19dea9adc7a87d73f4
BLAKE2b-256 c9ea4734c0b652dc5b250bc2db88ecc73a765c1edb00c81d56a31cc4378076ee

See more details on using hashes here.

File details

Details for the file type_intersections-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: type_intersections-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 5.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.2.2 CPython/3.10.9 Linux/6.0.19-4-MANJARO

File hashes

Hashes for type_intersections-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d4126b782c0fd543041c0d3e50aa31101ccf6df7d1939cb2573ccda5793db213
MD5 47163a0ba73cadc2eba95fb55da7c3d9
BLAKE2b-256 aae27572032fa4c0809d158a57d0a0998a4ca5cf662e5aeb3c1e5d15055995ec

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page