2
votes

I'm currently learning the Scala programming language (love it by the way) and have recently found out of implicit conversions. So i have my class Complex and its companion object. and in my companion object i want thees implicit conversions:

    implicit def convertToComplex(x: Double) = new Complex(x, 0);
    implicit def convertToComplex(x: Int) = new Complex(x, 0);
    implicit def convertToComplex(x: Float) = new Complex(x, 0);
    implicit def convertToComplex(x: Short) = new Complex(x, 0);
    implicit def convertToComplex(x: Long) = new Complex(x, 0);

in order to not bloat my Complex number class with overload for +,-,* and / for add number types.

So my question is:

Is there a shorter way to write the implicit conversions with some syntactic sugar of sorts? (i mean without all the overloads...)

Thanks in advance.

3
What is the type of the two coordinates? Is it fixed to say Double, or is Complex`` parametric? From the code snippet I gather it is not parametric (and so it probably types as Double so as to be able to accomodate all the input types), but I'd like a confirmation.Régis Jean-Gilles
Have you thought about using scala's built in numerics? It gives you something like this def plus[T: Numeric](x: T, y: T) = x + yNoah
@RégisJean-Gilles both the real and the imaginary parts are Double.boogie666

3 Answers

4
votes

You could do something like this

object ConvertComplex {
  case class Complex[T: Numeric](x: T, y: Int) {

    val nX = implicitly[Numeric[T]]

    def doSomething = nX.toInt(x) * y
    def doSomethingElse = nX.plus(x, nX.fromInt(y))
  }

  object Complex {
    implicit def convertToComplect[T: Numeric](x: T) = Complex(x, 0)
  }

}

And the test results:

def doSomething[T: Numeric](x: Complex[T]) = x.doSomething
def doSomethingElse[T: Numeric](x: Complex[T]) = x.doSomething

val double = 1: Double    //> double  : Double = 1.0
val int = 1: Int          //> int  : Int = 1
val float = 1: Float      //> float  : Float = 1.0
val short = 1: Short      //> short  : Short = 1
val long = 1: Long        //> long  : Long = 1

doSomething(double)       //> res0: Int = 0
doSomething(int)          //> res1: Int = 0
doSomething(float)        //> res2: Int = 0
doSomething(short)        //> res3: Int = 0
doSomething(long)         //> res4: Int = 0

doSomethingElse(double)   //> res5: Double = 1.0
doSomethingElse(int)      //> res6: Int = 1
doSomethingElse(float)    //> res7: Float = 1.0
doSomethingElse(short)    //> res8: Short = 1
doSomethingElse(long)     //> res9: Long = 1
3
votes

You need Integral rather than Numeric if you want Complex with method /.

Here is an almost completed solution:

scala> :paste
// Entering paste mode (ctrl-D to finish)

import scala.math.Integral

class Complex[T: Integral](val real: T, val imag: T) {
  import Integral.Implicits._
  def +(that: Complex[T]) = Complex(real+that.real, imag+that.imag)
  def -(that: Complex[T]) = Complex(real-that.real, imag-that.imag)
  def *(that: Complex[T]) = Complex(real*that.real - imag*that.imag, real*that.imag+imag*that.real)
  def /(that: Complex[T]) = {
    val d = that.real*that.real + that.imag*that.imag
    Complex((real*that.real + imag*that.imag)/d, (-real*that.imag+imag*that.real)/d)
  }
  override def toString: String = imag.signum match {
    case 1  => "" + real + "+" + imag +"i"
    case -1 => "" + real + "" + imag + "i"
    case _  => "" + real
  }
}

object Complex {
  import Integral.Implicits._
  def apply[T: Integral](real: T, imag: T): Complex[T] = new Complex[T](real, imag)
  object i extends Complex[Byte](0.toByte, 1.toByte)
  implicit class Real2Imag[T](val imag: T) {
    def *(v: i.type)(implicit ig: Integral[T]) = Complex(ig.zero, imag)
  }
  implicit def promote[U, V](c: Complex[U])(implicit ev: U => V, il: Integral[V]) =
    Complex(ev(c.real), ev(c.imag))
  implicit def real2complex[T: Integral](real: T) = Complex(real, implicitly[Integral[T]].zero)
  implicit val doubleIsIntegral = scala.math.Numeric.DoubleAsIfIntegral
}

// Exiting paste mode, now interpreting.

warning: there were 2 feature warnings; re-run with -feature for details
import scala.math.Integral
defined class Complex
defined object Complex

scala> import Complex._
import Complex._

scala> val c1 = 3 + 4*i
c1: Complex[Int] = 3+4i

scala> val c2 = 3.0 + 4.0*i
c2: Complex[Double] = 3.0+4.0i

scala> val c3 = c1/c2
c3: Complex[Double] = 1.0

scala> val c4 = 3 - 4*i
c4: Complex[Int] = 3-4i

scala> val c5 = c2*c4
c5: Complex[Double] = 25.0

You can write your pow method as this (Note how to generate a Complex one):

  def pow(n: Int): Complex[T] = {
    val one = Complex[T](implicitly[Integral[T]].one, implicitly[Integral[T]].zero)
    Iterator.iterate(one)(_*this).drop(n).next
  }

scala> i.pow(2)
res5: Complex[Byte] = -1

scala> i.pow(10)
res6: Complex[Byte] = -1

scala> (1+1*i).pow(4)
res7: Complex[Int] = -4

scala> (1+1*i).pow(5)
res8: Complex[Int] = -4-4i
0
votes

Yes, there is. I assume the Complex class has Double parameters. Then you can write an implicit conversion in one shot.

implicit def doubleToComplex[T <% Double](x: T): Complex = new Complex(x, 0)