Conversion and Promotion#

Return Types#

When a return type is not matched, Plum will attempt to convert the result to the right type.

from typing import Union

from plum import dispatch, add_conversion_method


@dispatch
def f(x: Union[int, str]) -> int:
    return x
>>> f(1)
1

>>> try: f("1")
... except Exception as e: print(f"{type(e).__name__}: {e}")
TypeError: Cannot convert `1` to `int`.

Plum will usually not know how to perform this conversion. You can tell Plum how the conversion should be done with add_conversion_method:

>>> add_conversion_method(type_from=str, type_to=int, f=int)

>>> f("1")
1

Conversion With convert#

The function convert can be used to convert objects of one type to another. This is also what is used to perform the conversion in the case the return type does not match.

Example:

from numbers import Number

from plum import convert


class Rational:
    def __init__(self, num, denom):
        self.num = num
        self.denom = denom
>>> convert(0.5, Number)
0.5

>>> try: convert(Rational(1, 2), Number)
... except Exception as e: print(f"{type(e).__name__}: {e}")
TypeError: Cannot convert `<Rational object at ...>` to `numbers.Number`.

The TypeError indicates that convert does not know how to convert a Rational to a Number. Let us implement that conversion:

from operator import truediv

from plum import conversion_method


@conversion_method(type_from=Rational, type_to=Number)
def rational_to_number(q):
    return truediv(q.num, q.denom)
>>> convert(Rational(1, 2), Number)
0.5

As above, instead of the decorator conversion_method, one can also use add_conversion_method:

>>> from plum import add_conversion_method

>>> add_conversion_method(type_from, type_to, conversion_function)

Promotion#

The function promote can be used to promote objects to a common type:

from plum import dispatch, promote, add_promotion_rule, add_conversion_method


@dispatch
def add(x, y):
    return add(*promote(x, y))


@dispatch
def add(x: int, y: int):
    return x + y


@dispatch
def add(x: float, y: float):
    return x + y
>>> add(1, 2)
3

>>> add(1.0, 2.0)
3.0

>>> try: add(1, 2.0)
... except Exception as e: print(f"{type(e).__name__}: {e}")
TypeError: No promotion rule for `int` and `float`.

You can add promotion rules with add_promotion_rule:

>>> add_promotion_rule(int, float, float)

>>> try: add(1, 2.0)
... except Exception as e: print(f"{type(e).__name__}: {e}")
TypeError: Cannot convert `1` to `float`.

>>> add_conversion_method(type_from=int, type_to=float, f=float)

>>> add(1, 2.0)
3.0