Python Overloaded

Function overloading is every day business in statically typed languages. Not all languages. Go has make it everything hard. 🙄 But function overloading in dynamic languages are not really sought after. Because the types are checked dynamically like so …

def parse_start_end(raw):
    if isinstance(raw, str):
        s, e = address.split(':')
    elif isinstance(raw, tuple):
        s, e = raw
        print('Parse error!')

TIL Pythong has a way to implement function overloading 🥳 via the singledispatch

from functools import singledispatch

def parse_start_end(raw):
    print('Parse error!')

def _(raw: str):
    start, end = raw.split(':')
    # some logic ... run loop?
    print(f"str: {start}-{end}")

def _(raw: tuple):
    start, end = raw
    # some logic ... run loop?
    print(f"tuple: {start}-{end}")

parse_start_end("1:10") # str: 1-10
parse_start_end((1, 10)) # tuple: 1-10
parse_start_end(22) # Parse error!
parse_start_end(list())  # Parse error!

What this buys us is a certain level of, for the lack of a better word, type affinity. Meaning, function is called based on the type of the parameters when you have functions by the same name a.k.a function overloading. This enables us to package code / logic based on types. All in Python. In fact, you can call one overload from another; if you have the right types in hand. See (in the code above) the overload that takes a str call the overload that takes tuple.

What you don’t get is complete type safety. Calls to parse_start_end with types that are not listed end up in the catch-all (def parse_start_end(raw)). You would wish for a compilation error for types that don’t match. Of course, there is no compilation error per se. Think of IDEs making use of mypy or other linters to report such errors early instead of at runtime.

One thing to note is that singledispatch is not a language construct. But a library implementation. Nonetheless, singledispatch is a great addition to our toolbelt.