For a library I’m building in Scala 3 (current target 3.3), I am trying to construct a type class hierarchy to express various functionality I want to require from the types I’m using and introducing.
So my current code base has something like
trait HasDimension[A] {
extension(a: A) def dim: Int
}
case class Simplex(vertices: Set)
given HasDimension[Simplex] with {
extension(a: Simplex) def dim: Int = a.vertices.size - 1
}
During other times working on this library, I have implemented a member method called dim
to do the exact work that HasDimension
is trying to guarantee, and I would like to provide a given
instance witnessing this. But when I write
given HasDimension[Cell] with {
extension(a: Cell) override def dim: Int = a.dim
}
I get infinite loops and hung execution when the lookup for a.dim
finds that I have an extension method on a
and goes to look up the extension method.
If instead I write something like
given HasDimension[Cell] with {
override def dim(a: Cell): Int = a.dim
}
I get an error message
error overriding method dim in trait HasDimension of type (t: Cell): Int;
method dim of type (t: Cell): Int is a normal method, cannot override an extension method
override def dim(t: Cell) = t.dim
I’m not fundamentally against changing my class hierarchies or picking a different approach to what I’m trying to do – but would need a few pointers to how. Except for where I get this syntax collision, type classes seem like the technique I need.
Down the line, I end up combining these type classes, so that a later definition that I use is
def HasBoundary[T] {
extension(t:T) def boundary: Chain[T]
}
def Cell[T] extends HasDimension[T] with HasBoundary[T]
And eventually I want to get to a point in the hierarchy where a user can specify the data types they want to work with (by instantiating a context object of some sort) and all the (topological) methods and functionality they want is instantiated for their choice of data types.