Companion Modules
In Flix every enum and type class declaration is associated with a companion module.
Enum Companions
When we declare an enum, its type and cases are automatically available inside its companion module. For example, we can write:
enum Color {
case Red,
case Green,
case Blue
}
mod Color {
pub def isWarm(c: Color): Bool = match c {
case Red => true
case Green => false
case Blue => false
}
}
Here the Color
type and the Red
, Green
, and Blue
cases are automatically
in scope within the companion Color
module.
Type Class Companions
Every type class declaration also gives rise to a companion module.
For example, we can define a type class Addable
for types whose elements can be added:
class Addable[t] {
pub def add(x: t, y: t): t
}
The Addable
type class implicitly introduces a companion module Addable
. We
typically use the companion module to store functionality that is related to the
type class.
For example, we could have:
mod Addable {
pub def add3(x: t, y: t, z: t): t with Addable[t] = add(add(x, y), z)
}
When accessing a member of Addable
, Flix will automatically look in both the
class declaration and its companion namespace. Consequently, Addable.add
refers to the type class member add
whereas Addable.add3
refers to the
function inside the Addable
module. Note that the add
signature is in the
scope of the Addable
module.
We should be aware that functions defined in the companion module of a type class cannot be overridden by instances of the associated type class. Thus we should only put members into the companion namespace when we do not intend to override them later.