Non-private class refers to private given instance in its type signature

I am trying to make a typeclass that defines various arithmetic operations for pairs of input types. Importantly, that typeclass needs to also define what the output type is.

I’ve got the following type class for this:

trait Arithmetic[L, R] {
  type Output

  def add(x: L, y: R): Output
  def sub(x: L, y: R): Output
}

And this works fine to define functions like so:

def add[X, Y](x: X, y: Y)(using arith: Arithmetic[X, Y]): arith.Output = arith.add(x, y)

But if I try to use this in a class definition, extending a base class using the output type, then I get an error message:

class Value[T](value: T)
class AddThing[X, Y](x: X, y: Y)(using arith: Arithmetic[X, Y]) extends Value[arith.Output](arith.add(x, y))
non-private class AddThing refers to private given instance arith
in its type signature Value[AddThing.this.arith.Output] {...}

I’d love help with what I should be doing here. Full (but minimal) example of the type of thing I’m trying to do is here. Thanks :folded_hands:

Well, I thought you just need to make arith public, so you can refer to the Output type on the public signature of AddThing.

class AddThing[X, Y](x: X, y: Y)(using val arith: Arithmetic[X, Y]) extends Value[arith.Output](arith.add(x, y))

But, that seems to trigger this error message:

The type of a class parent cannot refer to constructor parameters, but Value[AddThing.this.arith.Output] refers to arith

Thanks. And is there any way to work around that restriction? For my use case being able to pass it to the superclass is pretty essential.

@obeattie

Is the intent here to work with boxes of values in the form of Value, or does the planned API for AddThing impart anything more for client code using it?

If just a Value will do, how about simply:

def summedValue[X, Y](x: X, y: Y)(using arith: Arithmetic[X, Y]): Value[arith.Output] = new Value(arith.add(x, y))

Would that do?

Going a little further, would it be feasible for client code to work in the domain of left, right and result types directly as generic code, delegating to a given Arithmetic instance. Essentially this is a tagless final approach, with Arithmetic as an object algebra. What does Value add from the point of view of client code?

Of course, I don’t have the big picture of what you are trying to do - this is a probably a quite reduced example - so take my advice with a pinch of salt.

1 Like