Skip to main content

Multiple and Predicative Dispatch

This package enables extensible and context-sensitive dispatch to different code implementations that depend both on the annotated type of arguments and on predicates that are fulfilled by arguments.

Specifically, these dispatch decisions are arranged in a manner different than with blocks of if/elif or match/case statements, and also differently from inheritance hierarchies that resolve to a narrowest descendant type containing a given method.

This approach is often better than other paradigms both because of the clarity of implementation signatures and because of its flexible and simple extensibility.

A "dispatcher" is a namespace in which multiple callable names may live, and calling each one makes a runtime dispatch decision. These namespaces (classes, behind the scenes) can associate related functionality, and the collection of names and implementations in a namespace can all be imported by importing the one namespace object.

A default dispatcher named Dispatcher can be imported directly, but normally a factory function will generate new ones. The advantage of having a namespace object that maintains dispatchable implementations is that that object itself is indefinitely extensible.

Usage Example

In the API example below, the namespace created is called nums (e.g. for numeric functions with multiple implementations), but you can equally create others called, e.g. events or datasets or customers. A full application might utilize many namespace objects.

Within your application code that imports, e.g., the num namespace object, you can add many new function names and/or implementations for the already defined names.

from __future__ import annotations
from math import sqrt

from dispatch.dispatch import get_dispatcher
from primes import akw_primality, mr_primality, primes_16bit
nums = get_dispatcher("Numbers")

@nums
def is_prime(n: int & 0 < n < 2**16) -> bool:
    "Check primes from pre-computed list"
    return n in primes_16bit

@nums
def is_prime(n: 0 < n < 2**32) -> bool:
    "Check prime factors for n < √2³²"
    ceil = sqrt(n)
    for prime in primes_16bit:
        if prime > ceil:
            return True
        if n % prime == 0:
            return False
    return True

@nums(name="is_prime")
def miller_rabin(
    n: int & n >= 2**32, 
    confidence: float = 0.999_999,
) -> bool:
    "Use Miller-Rabin pseudo-primality test"
    return mr_primality(n, confidence)

@nums(name="is_prime")
def agrawal_kayal_saxena(
    n: int & n >= 2**32,
    confidence: float & confidence == 1.0,
) -> bool:
    "Use Agrawal-Kayal-Saxena deterministic primality test"
    return aks_primality(n)

# Bind to the Gaussian prime function (which _has_ a type annotation)
nums(name="is_prime")(gaussian_prime)  

@nums
def is_twin_prime(n: int):
    "Check if n is part of a twin prime pair"
    return nums.is_prime(n) and (nums.is_prime(n + 2) or nums.is_prime(n - 2))

print(nums) # -->
# Numbers with 2 function bound to 6 implementations (0 extra types)
nums.describe() # -->
# Numbers bound implementations:
# (0) is_prime
#     n: int ∩ 0 < n < 2 ** 16
# (1) is_prime
#     n: Any ∩ n < 2 ** 32
# (2) is_prime (re-bound 'miller_rabin')
#     n: int ∩ n >= 2 ** 32
#     confidence: float ∩ True
# (3) is_prime (re-bound 'agrawal_kayal_saxena')
#     n: int ∩ n >= 2 ** 32
#     confidence: float ∩ confidence == 1.0
# (0) is_twin_prime
#     n: int ∩ True

nums.is_prime(64_489)                        # True by direct search
nums.is_prime(64_487)                        # False by direct search
nums.is_prime(262_147)                       # True by trial division
nums.is_prime(262_143)                       # False by trial division
nums.is_prime(4_294_967_311)                 # True by Miller-Rabin test
nums.is_prime(4_294_967_309)                 # False by Miller-Rabin test
nums.is_prime(4_294_967_311, confidence=1.0) # True by AKS test
nums.is_prime(4_294_967_309, confidence=1.0) # False by AKS test
nums.is_prime(-4 + 5j)                       # True by Gaussian prime test
nums.is_prime(+4 - 7j)                       # False by Gaussian prime test
nums.is_twin_prime(617)                      # True (smaller of two)
nums.is_twin_prime(619)                      # True (larger of two)
nums.is_twin_prime(621)                      # False (not a prime)
nums.is_twin_prime(631)                      # False (not a twin)

Metadata

Release files for gnosis-dispatch 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gnosis-dispatch 1.0.1
File Size Uploaded
gnosis_dispatch-1.0.1.tar.gz 44.4 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for gnosis-dispatch 1.0.1
File Interpreter ABI Platform
gnosis_dispatch-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 44.4 MB

Release files / gnosis_dispatch-1.0.1.tar.gz

Download URL gnosis_dispatch-1.0.1.tar.gz
Size 44.4 MB
Tags Source
SHA-256 checksum
How to use checksums
6fc486c16bfcd1b73987fa88c894af8de35aee988fb71b2e31f9ef0517d75ae6
BLAKE2b-256 checksum
How to use checksums
4deaa8cbf106eb56f1e8dd0c462d89ff1ba0d9538b52a0825aa2febeffc5058b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.14.0

Release files / gnosis_dispatch-1.0.1-py3-none-any.whl

Download URL gnosis_dispatch-1.0.1-py3-none-any.whl
Size 9.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
655b54f06bbe1036f394b19bc1faf61a039856f3e8c32c4d1e4ca3ed808974d4
BLAKE2b-256 checksum
How to use checksums
8ad4034561c675f082c1a67849efb680b697ecc6f791d1698f36fb6022416808
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.14.0

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files

1.0.0

2 release files

0.9.1

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page