Search code examples
scalamatrixoperator-overloadingoperators

Left handed equivalent of apply in Scala


It's very easy to define something like a 2 dimensional Matrix class in Scala with an apply method that would let me elegantly access the values inside my Matrix. Quite simply one would do this :

class Matrix(val n: Int, val m: Int, val default: Double = 0) {
  val data: Array[Array[Double]] = Array.fill(n, m)(default)
  def apply(x: Int, y: Int): Double = data(x)(y)
}

This allows me to access elements in my matrix like so :

val matrix = new Matrix(3, 3)
println(matrix(2, 2))

What I'm after, however, is the ability to do the opposite, and actually assign values to a matrix using similar notation. Essentially I want the ability to write something like this :

matrix(2, 2) = 5

Is there any way to do this in Scala ? In C++ this is doable by overloading the parenthesis operator to return a reference rather than a copy (the former defines the setter and the latter the getter), and similarly in Python this is the distinction between the __getitem__ and __setitem__ magic methods (with the slight difference of applying to square brackets instead of parenthesis). Does Scala support such behavior or am I stuck having to either directly access the data member and/or just writing a setter function ?


Solution

  • Take Array#update as example:

      /** Update the element at given index.
       *
       *  Note the syntax `xs(i) = x` is a shorthand for `xs.update(i, x)`.
       *
       *  @param    i   the index
       *  @param    x   the value to be written at index `i`
       */
      def update(i: Int, x: T): Unit
    

    Try implementing an update:

    
    class Matrix(val n: Int, val m: Int, val default: Double = 0) {
      ...
      def update(x:Int, y: Int, value: Double): Unit =
       ???
    }
    
    
    matrix(2,2) = 5d
    

    EDIT:
    You can actually use:

    • def update(x:Int, y: Int, value: Double): Unit

    instead of:

    • def update(coord: (Int,Int), value: Double): Unit.

    and get exactly the syntax you desired.