0

This is a Scala-specific question.

Assume that you have a function (which you cannot modify) of several inputs, e.g.:

def test(x1: Int, x2:Int, x3: Int, x4: Int, x5: Int) = {
  //Some logic
} 

And assume that you have all the inputs for that function in a single array, e.g.:

val inputs = Array(1, 2, 3, 4, 5)

Is there a way to call test with that single array of inputs without explicitly inserting individual array elements (as in test(inputs(0),inputs(1),inputs(2),inputs(3),inputs(4)))?

This is particularly important for the case when I don't know the number of inputs and the number of elements in the array in advance (but know that they match).

verse
  • 236
  • 4
  • 9

3 Answers3

3

No that's not possible. It's possible to use an array for a function that expects varargs by using :_* syntax. Also, your question is contradictory:

the case when I don't know the number of inputs and the number of elements in the array in advance (but know that they match)

How could you not know the number of inputs or elements but know they match?

LuxuryMode
  • 33,401
  • 34
  • 117
  • 188
  • I'm using a number of functions written by somebody else that correspond to certain tables in a SQL database (the number of arguments for each of these functions is the same as the number of columns in the corresponding tables). I access the tables via JDBC and then want to run those functions to process the results of my queries. Is it at least possible to generate an in-place expansion of `inputs` to `inputs(0),inputs(1),...`? E.g. something along the lines of `test(for (i <- inputs) i)`? – verse Jul 29 '15 at 20:39
  • @verse have you considered just not doing that? Honestly, this sounds like the most unreasonable approach to anything I've ever heard. Figuring out how to pass an array as args to that function are the least of your worries. Have you asked that somebody why they have so little respect for you? – LuxuryMode Jul 29 '15 at 20:42
1

You can curry the function and then use one of the solutions proposed here.

For instance, using this technique:

class Acc[T](f: Function1[T, _]) {
  private[this] var ff: Any = f
  def apply(t: T): this.type = {
    ff = ff.asInstanceOf[Function1[T,_]](t)
    this
  }
  def get = ff match { 
    case _: Function1[_,_] => sys.error("not enough arguments")
    case res => res.asInstanceOf[T]
  }
}

def test(x1: Int, x2:Int, x3: Int, x4: Int, x5: Int) = {
  //Some logic
} 

val inputs = Array(1, 2, 3, 4, 5)

inputs.foldLeft(new Acc((test _).curried))((acc, i) => acc(i)).get

Not extremely safe, but it should work

Community
  • 1
  • 1
Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
  • Gabriele, and would this work if instead of a function I had a class `class test (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int)` and wanted to run a constructor with a single array of inputs? – verse Jul 29 '15 at 20:55
  • yes, you can curry the constructor: http://stackoverflow.com/questions/3862717/scala-curried-constructors – Gabriele Petronella Jul 29 '15 at 21:38
0

You can use Java reflection (or Scala reflection, but Java's one is sufficient for this). The below is a quick and dirty solution, which assumes you have a class Test which contains exactly one test method:

val m = classOf[Test].
  getMethods.find(_.getName == "test").
  getOrElse(throw new Exception("No method called test"))

// inputs must be Array[Object], not Array[Int] as in your example
m.invoke(instanceOfTest, inputs)

This is rarely a good idea, however.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487