Reflexive Interfaces in Go
In languages with typeclasses, like Rust
, or Haskell
, you can have
an interface that uses its type in different positions, like:
class Group a where
unit :: a
combine :: a -> a -> a
invert :: a -> a
In Go
, on the other hand, you can only really enforce some type
as the “first argument”, e.g.:
type Consumer interface {
Consume(string)
}
There are many situations where you’d want to be able to reference the type implementing an interface, for example when representing concepts from algebra.
One not very type-safe way of doing this is casting:
type Group interface {
Combine(that Group) Group
Invert() Group
}
Then, when implementing this for a concrete group, you’d cast to the right type:
func (x *mygroup) Combine(that Group) {
casted := that.(*mygroup)
...
}
The idea is that you never mix different instances of Group
together.
With generics, you’d be able to do something more type-safe:
type Group[T] interface {
Combine(that T) T
Invert() T
}
And then consistently doing:
func foo[T Group[T]](x T) {
...
}
To ensure that the types lign up as desired.
One problem with both of these approaches is that there’s no way to model nullary operations, like:
unit :: a
I still don’t really know of a good way to model something like this in Go.