In many programming languages, when you define a new type or object, you can also define how it behaves. But often, there’s no automatic way to check that your new type still behaves the way it’s supposed to — especially if it’s meant to “act like” another type.
In Julia, this is even more open-ended: you can subtype an abstract type and start overloading some other nerd’s functions, but nothing forces your implementation to meet expectations. This makes code flexible, but also fragile. You get a lot of freedom, but you’re roaming around in the Wild West.
Why don’t we use tests in Julia to define contracts? That means: when you define an abstract type (or any kind of interface), you also define a test suite that expresses the properties all subtypes should satisfy. Tests are assertions, mathematical propositions. Julia, with its powerful reflection capacities, could surely do something exciting with that.
For example, if something is a SortedCollection
, it should always return its elements in order — and that should be part of its test contract. Then, when someone extends SortedCollection
, those tests automatically run against their implementation.
This approach solves two problems at once. First, it prevents silent breakage: if a new type doesn’t behave as expected, it fails the contract. Second, it helps the compiler and runtime know what parts of the code are likely to be used — which helps with things like precompilation in Julia. In a language where dispatch is dynamic and types are open-ended, knowing the common execution paths ahead of time is probably a good thing.
Go to next post ▤ in vault series.