views:

320

answers:

3

Hi, I am very new to Scala.

I want to implement a generic matrix class "class Matrix[T]". The only constraint on T should be that T should implement a "+" and a "*" mothod/function. How do I go about doing this?

For example I want to be able to use both Int, Double, and my own defined types e.g. Complex

I was thinking something along the lines:

class Matrix[T <: MatrixElement[T]](data: Array[Array[T]]) {
   def *(that: Matrix) = ..// code that uses "+" and "*" on the elements
}
abstract class MatrixElement[T] {
    def +(that: T): T
    def *(that: T): T 
}
implicit object DoubleMatrixElement extends MatrixElement[Double]{
    def +(that: Double): Double = this + that
    def *(that: Double): Double = this * that 
}
implicit object ComplexMatrixElement extends MatrixElement[Complex]{
    def +(that: Complex): Complex = this + that
    def *(that: Complex): Complex = this * that 
}

Everything type checks but I still can't instantiate a matrix. Am I missing an implicit constructor? How would I go about making that? Or am I completely wrong about my method?

Thanks in advance Troels

+3  A: 

You can use Numeric for Scala 2.8 for that. It is describe here. It would replace MatrixElement and its implementations:

class Matrix[T : Numeric](data: Array[Array[T]]) {
   def *(that: Matrix[T]) = //
}
Thomas Jung
I considered Numeric. But I don't really see how that would work for my own types e.g. Complex.I would think that Complex then would need to extend Numeric. Which first of all would require me to implement many more methods than just + and *. Amongst these ordering - As far as I know there is no strict ordering on complex numbers. The key point is that I need Matrix to work on any Types that just full fill that methods + and * are implemented.
Troels Blum
There are a lot of methods to implement if you only need + and *. But you can still create something like Numeric with just these two methods. This should be two much work. (And maybe come back later and replace it with Numeric if worthwhile.)
Thomas Jung
@troels You can always order by the real part, or just plain return "0" for all comparisons. And you can always "implement" the methods with `error("Undefined method")`. Notice, though, that `Complex` would not _extend_ `Numeric`. Instead, there would be an instance of a `Numeric[Complex]`.
Daniel
How does one go about implementing a subtype of Numeric[T]?I have been looking for at guide on this but haven't found any.Also posted it as a seperate question: http://stackoverflow.com/questions/2274718/scala-implementing-a-subtype-of-numerict
Troels Blum
+2  A: 

Here's how the Numeric solution would look:

// ': Numeric[T]' adds an implicit parameter to the constructor,
// which allows T to be used in arithmetic expressions.
class Matrix[T: Numeric](val data: Array[Array[T]]) {
   def *(that: Matrix[T]) = {
       val nt = implicitly[Numeric[T]]
       import nt._  // This imports an Implicit View to allow operator syntax

       this.data(0)(0) * that.data(0)(0)
       // etc
   }
}
retronym
`T: Numeric[T]` should be `T: Numeric`. Do you write this without REPL? :-)
Thomas Jung
Oops! Caught me out :)
retronym
A: 

Finally found the answer :-) I think I wasn't that far off in my first try. Here it goes: (written for scala 2.8)

trait MatrixElement[T] {
    def +(that: T): T
    def *(that: T): T 
}

object MatrixElement {
    implicit def intToMatrixElement(x : Int) = new MatrixElement[Int] {
        def +(y : Int) = x + y
        def *(y : Int) = x * y
    }
    implicit def doubleToMatrixElement(x : Double) = new MatrixElement[Double] {
        def +(y : Double) = x + y
        def *(y : Double) = x * y
    }
    implicit def complexToMatrixElement(x : Complex) = new MatrixElement[Complex] {
        def +(y : Complex) = x + y
        def *(y : Complex) = x * y
    }
}

class Matrix[T  <% MatrixElement[T] : ClassManifest ](d: Array[Array[T]]) {
    def *(that: Matrix) = ..// code that uses "+" and "*" on the elements
}

Now I can do stuff like:

scala> new Matrix(Array(Array(1,0),Array(0,1)))
res0: Matrix[Int] = 
1 0 
0 1 

scala> new Matrix(Array(Array(new Complex(0),new Complex(1)),Array(new Complex(1),new Complex(0))))
res9: Matrix[Complex] = 
(0.0,0.0i) (1.0,0.0i) 
(1.0,0.0i) (0.0,0.0i) 
Troels Blum