Jay Taylor's notes

back to listing index

parameters - scala tuple unpacking - Stack Overflow

[web search]
Original source (stackoverflow.com)
Tags: scala tuple parameters fancy stackoverflow.com
Clipped on: 2012-09-25

I know this question has come up many times in different ways. But it is still not clear to me. Is there a way to achieve the following.

def foo(a:Int, b:Int) = {}

foo
(a,b) //right way to invoke foo

foo
(getParams) // is there a way to get this working without explicitly unpacking the tuple??

def getParams = {
   
//Some calculations
   
(a,b)  //where a & b are Int
}
asked Aug 25 '10 at 16:15
Image (Asset 1/4) alt= 320112

70% accept rate
  upvote
 flag
What if foo happens to be the constructor of some class? – scout Aug 25 '10 at 16:26
add comment

3 Answers

It's a two step procedure. First turn foo into a function, then call tupled on it to make it a function of a tuple.

(foo _).tupled(getParams)
answered Aug 25 '10 at 16:23
Image (Asset 2/4) alt= 9,19311841
1 upvote
 flag
Would it not be cleaner if Scala just thought of arguments as Tuples to start with? – Henry Story Feb 19 at 21:10
2 upvote
Yes, it would be a lot cleaner if Scala would unify it's handling of tuples and argument lists. From what I've heard, there are a lot of non-obvious edge-cases that would need careful handling to make that happen. As far as I know, unification of tuples and argument lists is not on the Scala roadmap at this time. – Dave Griffith Feb 19 at 21:29
add comment

Function.tupled(foo _)(getParams) or the one suggested by Dave.

EDIT:

To respond to your comment:

What if foo happens to be the constructor of some class?

In that case, this trick won't work.

You can write a factory method in the companion object of your class and then obtain the tupled version of its apply method using one of the aforementioned techniques.

scala> class Person(firstName: String, lastName: String) {
     
|   override def toString = firstName + " " + lastName
     
| }
defined
class Person

scala
> object Person {
     
|   def apply(firstName: String, lastName: String) = new Person(firstName, lastName)
     
| }
defined module
Person

scala
> (Person.apply _).tupled(("Rahul", "G"))
res17
: Person = Rahul G

With case classes you get a companion object with an apply method for free, and thus this technique is more convenient to use with case classes.

scala> case class Person(firstName: String, lastName: String)
defined
class Person

scala
> Person.tupled(("Rahul", "G"))
res18
: Person = Person(Rahul,G)

I know that's a lot of code duplication but alas... we don't have macros (yet)! ;)

answered Aug 25 '10 at 16:24
Image (Asset 3/4) alt= 30.2k369156
3 upvote
 flag
In the last example here, you could shave off a bit... Companion objects for case classes always extend the appropriate FunctionN trait. So the last line could be Person.tupled(("Rahul", "G")) It's handy to do this in hand-written companion objects too. – David Winslow Aug 26 '10 at 0:15
  upvote
 flag
@David: Edited, thanks. :-) – missingfaktor Aug 26 '10 at 2:01
add comment

@dave-griffith is dead on.

You can also call:

Function.tupled(foo _)

If you want to wander into "way more information than I asked for" territory, there are also methods built into partially applied functions (and on Function) for currying. A few input/output examples:

scala> def foo(x: Int, y: Double) = x * y
foo
: (x: Int,y: Double)Double

scala
> foo _
res0
: (Int, Double) => Double = <function2>

scala
> foo _ tupled
res1
: ((Int, Double)) => Double = <function1>

scala
> foo _ curried
res2
: (Int) => (Double) => Double = <function1>

scala
> Function.tupled(foo _)
res3
: ((Int, Double)) => Double = <function1>

// Function.curried is deprecated
scala
> Function.curried(foo _)
warning
: there were deprecation warnings; re-run with -deprecation for details
res6
: (Int) => (Double) => Double = <function1>

Wherein the curried version is invoked with multiple argument lists: scala> val c = foo _ curried c: (Int) => (Double) => Double =

scala> c(5)
res13
: (Double) => Double = <function1>

scala
> c(5)(10)
res14
: Double = 50.0

Finally, you can also uncurry/untuple if needed. Function has builtins for this:

scala> val f = foo _ tupled
f
: ((Int, Double)) => Double = <function1>

scala
> val c = foo _ curried
c
: (Int) => (Double) => Double = <function1>

scala
> Function.uncurried(c)
res9
: (Int, Double) => Double = <function2>

scala
> Function.untupled(f)
res12
: (Int, Double) => Double = <function2>
answered Aug 25 '10 at 16:31
Image (Asset 4/4) alt= 2,954813
add comment

Your Answer

 
community wiki

Not the answer you're looking for? Browse other questions tagged or ask your own question.