17

I am trying to send the result of a method call's tuple, as part of the argument list for another method.

Target method

def printResult(title: String, result: Int, startTime: Long, endTime: Long)

Return from method, partial argument list

def sendAndReceive(send: Array[Byte]): (Int, Long, Long)

In other words, I am trying to call printResult(String, (Int, Long, Long)). If the method return signature matches the method call, then I could have used

(printResult _).tupled(sendAndReceive(heartbeat))

This results in syntax error

printresult("Hi", Function.tupled(sendAndReceive(heartbeat))

Workaround

I am resorting to manually unpacking the tuple, then using it when calling the method

val tuple = sendAndReceive(heartbeat)
printResult("Heartbeat only", tuple._1, tuple._2, tuple._3)

Is there a more elegant way to unpack and send a tuple as part of argument list?

References

Scala: Decomposing tuples in function arguments

Invoke a method using a tuple as the parameter list

Will tuple unpacking be directly supported in parameter lists in Scala?

Tuple Unpacking in Map Operations

Community
  • 1
  • 1
Hanxue
  • 12,243
  • 18
  • 88
  • 130

4 Answers4

23

You can do the following:

val (result, startTime, endTime) = sendAndReceive(heartbeat)
printResult("Heartbeat only", result, startTime, endTime)
Carl
  • 826
  • 1
  • 7
  • 14
  • 5
    Thanks, I agree this works. But can I do it without unpacking the tuple? – Hanxue Jun 13 '14 at 03:27
  • Well that's a different question to the one you aksed originally: "more elegant way to unpack". :-) Now you want to do it without unpacking. – Carl Jun 13 '14 at 03:32
  • 1
    I don't think I express the question clear enough :) I upvoted though. I want to do something like `invokeMethod(arg1, arg2, tuple)` – Hanxue Jun 13 '14 at 03:38
  • Of course, if you can you change or overload the method signature of def printResult(title: String, result: Int, startTime: Long, endTime: Long) to def printResult(title: String, t: [Int, Long, Long]) you don't have to unpack the tuple before you call printResult. – Carl Jun 13 '14 at 12:08
5

Are you attached to this function signature?

def printResult(title: String, result: Int, startTime: Long, endTime: Long)

If it is your code and you can modify it, then you can try and use currying instead like this:

def printResult(title: String)(result: Int, startTime: Long, endTime: Long)

Then you can execute it like this:

printResult("Curried functions!") _ tupled(sendAndReceive(heartbeat))
kapunga
  • 436
  • 3
  • 7
1

One approach involves case classes for the tuple, for instance like this,

case class Result(result: Int, startTime: Long, endTime: Long) {
  override def toString() = s"$result ($startTime to $endTime)"
}

def sendAndReceive(send: Array[Byte]): Result = {
  // body
  Result(1,2,3)
}

def printResult(title: String, res: Result) = println(title + res)
elm
  • 20,117
  • 14
  • 67
  • 113
  • 1
    Thanks for the suggestion. Yes, case class and type definitions are possible. I am looking for something concise and expressive. E.g. Python's kwargs – Hanxue Jun 13 '14 at 03:27
  • @hanxue kwargs approach may work assuming all elements in the tuple belong to the same type; yet consider the type for (1,2,3).productIterator is Iterator[Any] although a priory we know all elements are Int. – elm Jun 13 '14 at 03:39
1

This can indeed be achieved without unpacking the tuple using shapeless (and tupling the function as you did):

import shapeless.syntax.std.tuple._

(printResult _).tupled("Hi" +: sendAndReceive(???))

"Hi" +: sendAndReceive(???) just prepends the value "Hi" to the tuple returned by sendAndReceive.

Alex Archambault
  • 985
  • 1
  • 8
  • 16