Interfaces and variants

Interfaces

An interface type is like a union, but does not declare its case types.
Instead, each case type declares itself a case of the interface.

import keen/math/math main void() a shape = circle 1 b shape = square 2 log area a log area b shape interface area float() circle record(radius float) shape case area float(a circle) pi * a.radius ** 2 square record(width float) shape case area float(a square) a.width ** 2

Strong interfaces

There's no way to retrieve the case type given a reference to an interface.
The only thing you can do with an interface value is call its methods.
This is usually a good thing as it makes an interface a meaningful specification of what a value is actually used for.
If you want to match on an interface, use a variant instead.

Interface mutability

As with a union, case types of an interface can have at most the interface's mutability.

main void() a i = r 0 log update a log update a i interface mut update nat() r record mut, i case count mut nat update nat(a r) a.count +:= 1 a.count

Variants

variants are like interfaces, but support match expressions.
Or to put it another way, a variant is like a union where the case types do not have to be known up-front.
These aren't often needed, but the exception type is an example variant type. It's a good example where it would be impractical to declare all case types up-front.

main void() a shape = circle 1 log match a as circle "circle {a.radius}" as square "square {a.width}" else "some other type" shape variant circle record(radius float) shape case square record(width float) shape case

Restrictions

  • Since a case type must explicitly case an interface or variant, they can't contain already-declared types like nat.
  • Auto functions won't work on interfaces or variants.