Como configurar a conversão implícita para permitir aritmética entre tipos numéricos?
Eu gostaria de implementar uma classeC
para armazenar valores de vários tipos numéricos e booleanos. Além disso, eu gostaria de poder operar em instâncias dessa classe, entre tipos, convertendo sempre que necessárioInt --> Double
eBoolean -> Int
, ou seja, para poder adicionarBoolean + Boolean
, Int + Boolean
, Boolean + Int
, Int + Double
, Double + Double
etc., retornando o menor tipo possível (Int
ouDouble
) quando possível.
Até agora eu vim com isso:
abstract class SemiGroup[A] { def add(x:A, y:A):A }
class C[A] (val n:A) (implicit val s:SemiGroup[A]) {
def +[T <% A](that:C[T]) = s.add(this.n, that.n)
}
object Test extends Application {
implicit object IntSemiGroup extends SemiGroup[Int] {
def add(x: Int, y: Int):Int = x + y
}
implicit object DoubleSemiGroup extends SemiGroup[Double] {
def add(x: Double, y: Double):Double = x + y
}
implicit object BooleanSemiGroup extends SemiGroup[Boolean] {
def add(x: Boolean, y: Boolean):Boolean = true;
}
implicit def bool2int(b:Boolean):Int = if(b) 1 else 0
val n = new C[Int](10)
val d = new C[Double](10.5)
val b = new C[Boolean](true)
println(d + n) // [1]
println(n + n) // [2]
println(n + b) // [3]
// println(n + d) [4] XXX - no implicit conversion of Double to Int exists
// println(b + n) [5] XXX - no implicit conversion of Int to Boolean exists
}
Isso funciona para alguns casos (1, 2, 3), mas não para (4, 5). O motivo é que há um aumento implícito do tipo de menor para maior, mas não o contrário. De certa forma, o método
def +[T <% A](that:C[T]) = s.add(this.n, that.n)
de alguma forma, precisa ter um método de parceiro parecido com:
def +[T, A <% T](that:C[T]):T = that.s.add(this.n, that.n)
mas isso não é compilado por dois motivos: primeiro, o compilador não pode converterthis.n
digitarT
(apesar de especificarmos o limite de visualizaçõesA <% T
) e, em segundo lugar, que mesmo que fosse capaz de converterthis.n
, após o tipo apagar os dois+
métodos tornam-se ambíguos.
Desculpe isso é muito longo. Qualquer ajuda seria muito apreciada! Caso contrário, parece que eu tenho que escrever todas as operações entre todos os tipos explicitamente. E ficaria peludo se eu tivesse que adicionar tipos extras (Complex
é o próximo no menu ...).
Talvez alguém tenha outra maneira de conseguir tudo isso? Parece que há algo simples que estou ignorando.
Desde já, obrigado!