1

Say I have an e.g. two-dimensional array, and I'm storing some indexes in tuples:

val testArray = Array.ofDim[Double](3, 4)
val ixs = (1,2)

I'd like to use those tuples directly, e.g. testArray(ixs). However, Function.tupled(testedArray _) returns "_ must follow method; cannot follow Array[Array[Double]]".

Is this because Array is not actually a subtype of Function3? If so, how to go around this limitation? Should I use implicits to extend ArrayOps or something similar? Currently, I'm storing the data in a Map as a workaround.

1 Answer 1

2

Arrays of arrays are not given special treatment; they're just arrays of (something). Thus, there's no special way to access them via tuples. But as you've suggested, you can create such a way.

You can

implicit class ArrayOps2D[@specialized T](xss: Array[Array[T]]) {
  def apply(ij: (Int, Int)) = xss(ij._1)(ij._2)
  def apply(i: Int, j: Int) = xss(i)(j)
  def update(ij: (Int, Int), t: T) { xss(ij._1)(ij._2) = t }
  def update(i: Int, j: Int, t: T) { xss(i)(j) = t }
}

You might think of doing

implicit class ArrayOps2D[T](val xss: Array[Array[T]]) extends AnyVal {
  def apply(ij: (Int, Int)) = xss(ij._1)(ij._2)
  def apply(i: Int, j: Int) = xss(i)(j)
  def update(ij: (Int, Int), t: T) { xss(ij._1)(ij._2) = t }
  def update(i: Int, j: Int, t: T) { xss(i)(j) = t }
}

but this doesn't work as well in my opinion. Due to implementation limitations, you can't specialize an AnyVal. Furthermore, the former is probably better if you are using primitives a lot since it avoids boxing the primitives (and the JVM can handle avoiding object creation, hopefully), while the latter is more efficient if you have non-primitives most of the time (e.g. strings) since you don't (formally) create an object. But your example uses primitives.

In any case, if you do this you'll have seamless two-index addressing with tuples and pairs of arguments (as I've written it). You cannot use the update methods completely seamlessly, though! They will mostly work, but they won't automatically promote numeric types. So if you have doubles and you write a(1,2) = 3 it will fail, because it doesn't find an update(Int, Int, Int) method, and doesn't think to use the update(Int, Int, Double). But you can fix that yourself by doing the conversion (or in this case writing 3d).

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the comprehensive discussion of the trade-offs between the two approaches.
Also, you can now (Scala 2.10+) "specialize" AnyVal with value classes, although implementation-wise, it's not as straightforward as simple "subclassing".
@TheTerribleSwiftTomato - I'm not sure what you mean. You can't actually use the specialized keyword in 2.10, and I already cover the generic unboxed-array-boxed-elements version under "you might think of doing".
Heh, a little miscommunication here, and due to my inferior knowledge of Scala nonetheless - I wasn't aware of the specialized keyword and assumed you meant the general OOP term. In that context, yes, that was covered under the section of your answer you mentioned.
@TheTerribleSwiftTomato - Fair enough. (Technically it's an annotation, not a keyword--I misspoke above.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.