Help with covariant types in trait implementation

Hello,
I wrote this code:

sealed trait Currency {

def +[A <: Currency](c: A): A
def -[A <: Currency](c: A): A
def canDeduct[A <: Currency](c: A): Boolean
def toString(): String
}

case class Credit(amount: Float) extends Currency {

def +(c: Credit): Credit = Credit(amount + c.amount)
def -(c: Credit): Credit = Credit(amount - c.amount)
def canDeduct(c: Credit): Boolean = amount >= c.amount
override def toString(): String = “%1.2f”.format(amount)
}

Scala compiler says that there are 3 unimplemented methods in class Credit.
I’m a little lost, I thought that Credit class fulfilled covariant type requirements (it extends Currency trait) defined in Currency trait.
How can I make this work?
Thanks,

M

Hello,

In class Credit, the type parameter A is not bound to be Credit, it can be
any other subtype of Currency. You could make it a parameter of Currency
and set it to Credit when extending Currency to Credit:

sealed trait Currency[A <: Currency] {def +(c: A): Adef -(c: A): Adef
canDeduct(c: A): Booleandef toString(): String}case class Credit(amount:
Float) extends Currency[Credit] {def +(c: Credit): Credit = Credit(amount +
c.amount)def -(c: Credit): Credit = Credit(amount - c.amount)def
canDeduct(c: Credit): Boolean = amount >= c.amountoverride def toString():
String = “%1.2f”.format(amount)}

Covariance does not apply here, because you have not declared A to be
covariant, and it cannot be covariant, because you have methods that take
arguments of type A.

Best, Oliver

Hello Oliver,
I tried to implement a solution similar to yours but I ran into trouble with “recursive” type declaration:
sealed trait Currency[A <: Currency]
The second use of Currency type requires a type parameter. This compiles:
sealed trait Currency[A <: Currency[_]]
But it does not work later on.

Does anyone know of some other way to solve this?
Thanks,

M

This seems to work:

sealed trait Currency[A] {

def +(c: A): A
def -(c: A): A
def canDeduct(c: A): Boolean
def toString(): String
}

case class Credit(amount: Float) extends Currency[Credit] {

def +(c: Credit): Credit = Credit(amount + c.amount)
def -(c: Credit): Credit = Credit(amount - c.amount)
def canDeduct(c: Credit): Boolean = amount >= c.amount
override def toString(): String = “%1.2f”.format(amount)
}

Thanks,

M

What kind of problems you get later on?

Hi Oliver,
I realized the problem I was trying to solve would not get solved through this design.
The compiler was reporting the same error (3 unimplemented methods), but I’m going to try something else.
Thank you for your help,

M

You need f-bounded polymorphism (recursive type bounds) to solve this kind of problem. Here’s a simple example:

scala> trait Numeric[X <: Numeric[X]] { def add(x: X): X }
defined trait Numeric

scala> class Nat(val i: Int) extends Numeric[Nat] { def add(x: Nat): Nat = new Nat(i + x.i) }
defined class Nat
4 Likes

Thank you, that’s what I was looking for.
Thanks,

M