Type Classes

Austral doesn’t have operator overloading. That is, you can’t write:

function foo(x: Int32): Unit;

function foo(x: Buffer): Int32;

Because the compiler will complain that there are two functions with the same name. But suppose we want to print things. Normally, we’d have to define a printT function for each type T. This works, it’s not too verbose, but it doesn’t let you reason about interfaces: to know if a type is printable, you have to manually look for a function called something like printFoo for the type.

Type classes let us have operator overloading in a way that is principled and allows us to reason about interfaces.

A type class is an interface that types can implement, equivalently, it defines the set of types that implement that interface. Type classes have instances: an instance is the implementation of a type class for a particular type.

For example, you could have a type class for types that can be printed:

typeclass Printable(T: Type) is
    generic [R: Region]
    method printRef(ref: &[T, R]): Unit;

And here’s how you would define an instance for the Int64 type:

instance Printable(Int64) is
    generic [R: Region]
    method printRef(ref: &[Int64, R]): Unit is
        -- ...