Allow update method accept varargs of its first parameter

I want to design an NDArray struct like numpy’s ndarray, which may have various shape and dimenssion.
The ideal data assessing of NDArray is something as:

val nda = NDArray(Array.range(0, 9), shape=Seq(3, 3)) // A 2D NDArray
nda(1, 1) = 100   // update the value of position (1, 1)
println(nda(1, 1))  // get the value of position (1, 1)

// or a 3d array
val nda3 = NDArray(Array.range(0, 24), shape=Seq(2, 3, 4)) 
nda3(1, 2, 3) = 123
println(nda3(1, 2, 3))

A not work implementation:

class NDArray[A](val data: Array[A], val shape: Seq[Int]):
    def strides: Seq[Int] = shape.scanRight(1)(_ * _).tail
    def offset(index: Int*): Int = index.zip(strides).map(_ * _).sum
    def apply(index: Int*): A = data(offset(index*))
    // def update(index: Int*, value: A): Unit = data.update(offset(index*), value)
    // def update(index: Int*)(value: A): Unit = data.update(offset(index*))(value)

The update method does not compile since current update only accept two parameters, and its first parameter cannot be a varargs.

1 Like

That’s unfortunate. Can you try a tuple instead? It’ll mean a couple extra parentheses, but it’s probably better than doing Seq(...) everywhere. You might also be able to make the update method take Int* and return an object with a := method to make it look similar to a plain =, although I don’t know how much overhead both of those would have.

Maybe let update take Any* and define as a macro that inspects the call and re-rewrites it. The curried translation would be nice.

As a footnote, I noticed this syntax works in Scala 2 but not Scala 3.

scala> c("X") = Seq(1,1):_*