Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Test generic code

To test a generic function, you have to pick a type to test it at. The obvious choice, Int, can hide bugs: a property may pass because of something particular to integers, such as arithmetic coincidences, or because a function quietly relies on behaviour only Int has.

PolyA, PolyB, and PolyC are opaque stand-in types for this (Haskell QuickCheck’s Test.QuickCheck.Poly). Each holds an integer, but supports only equality, ordering, hashing, and printing. Testing a generic function at PolyA shows that it works for any type with just those operations.

from proptest import check, PolyA

def reverse[T: Copyable](xs: List[T]) -> List[T]:
    var out = List[T]()
    for i in range(len(xs) - 1, -1, -1):
        out.append(xs[i].copy())
    return out^

def main() raises:
    def reverse_twice(xs: List[PolyA]) -> Bool:
        return reverse(reverse(xs)) == xs

    check(reverse_twice)
    print("passed")

They print with their tag, so a counterexample is easy to read: given([A(0), A(1)]). Use different stand-ins for different type parameters (Dict[PolyB, PolyC]), so that a function that mixes them up fails to compile, or fails the test.

Poly[tag] makes more stand-in types: Poly["Key"] prints as Key(3).