2

What is the difference between these two code blocks?

def measure[A](histogram: Histogram)(thunk: ⇒ A): A = {
  val start = RelativeNanoTimestamp.now
  try thunk finally {
    val latency = NanoInterval.since(start).nanos
    histogram.record(latency)
}

def measure[A](histogram: Histogram, thunk: ⇒ A): A = {
  val start = RelativeNanoTimestamp.now
  try thunk finally {
    val latency = NanoInterval.since(start).nanos
    histogram.record(latency)
}

Github Source

3
  • 2
    In the 1st, the two arguments are curried, in the 2nd they are not. What is it that you're trying to learn/solve? Commented Jun 23, 2016 at 22:23
  • @jwvh What is benefit of currying vs. the alternative? Thank you for replying! Commented Jun 23, 2016 at 22:52
  • @jwvh I see that you can partially call a function with currying. docs.scala-lang.org/tutorials/tour/currying.html Commented Jun 23, 2016 at 22:56

1 Answer 1

3

=> A is a lazy parameter. It will be evaluated when referred to in the function. It can be a function producing a value, or just a value.

The main difference between single and multiple parameter lists as in your example:

def measure[A](histogram: Histogram)(thunk: ⇒ A)
def measure[A](histogram: Histogram, thunk: ⇒ A)

(not considering implicits and type inference) is how you apply a function:

scala> def f[A](i: Int)(p: => A): A = { p }
f: [A](i: Int)(p: => A)A

scala> f(1)(2)
res0: Int = 2

scala> f(1){ println("something") }
something

scala> f(1){
     |   println("test")
     | }
test

scala> def f2[A](i: Int, p: => A): A = { p }
f2: [A](i: Int, p: => A)A

scala> f2(1, 2)
res4: Int = 2

scala> f2(1, println("test"))
test

scala> f2(1, { println("test") })
test

See that f with multiple param lists allows us to write in this style: f(...){...}, while f2 is a bit less elegant if you have multiline code block as a second argument: f(..., {...}).

Furthermore if you do lot's of currying/partial application then f2 is a bit easier to deal with than f:

scala> val f_withFirstArg = f(1) _
f_withFirstArg: (=> Nothing) => Nothing = <function1>

scala> val f2_withFirstArg = f2(1, _)
<console>:8: error: missing parameter type for expanded function ((x$1) => f2(1, x$1))
       val f2_withFirstArg = f2(1, _)
                                   ^

We have to specify parameter type explicitly, type inference fails short:

scala> val f2_withFirstArg = f2(1, _: String)
f2_withFirstArg: String => String = <function1>

If you want to get technical about it, then it's worth pointing out that they are actually of a different type:

scala> :type f _
Int => ((=> Nothing) => Nothing)

scala> :type f2 _
(Int, => Nothing) => Nothing

f is a function that takes an Int and returns another function that takes type A and will produce type A. f2 is a function that takes 2 args: Int and A and returns A.

It really depends on your code. If you need to do lots of partial application or need less annotation due to type inference shortcomings then use multiple param lists. Otherwise there is no need to overcomplicate things and use regular single param list functions.

Finally you can always convert from one type of function to another as long as it makes sense:

scala> f2 _
res13: (Int, => Nothing) => Nothing = <function2>

scala> f2 _ curried
warning: there were 1 feature warning(s); re-run with -feature for details
res14: Int => ((=> Nothing) => Nothing) = <function1>

scala> f _ curried
<console>:9: error: value curried is not a member of Int => ((=> Nothing) => Nothing)
              f _ curried
                  ^

scala> f _ tupled
<console>:9: error: value tupled is not a member of Int => ((=> Nothing) => Nothing)
              f _ tupled
                  ^

scala> f2 _ tupled
warning: there were 1 feature warning(s); re-run with -feature for details
res17: ((Int, => Nothing)) => Nothing = <function1>

Notice that we can't make f curried because it already is. We can't make f tupled because it would not change anything. However, we can convert f2 into f using curried:

scala> :type f _
Int => ((=> Nothing) => Nothing)

scala> :type f2 _ curried _
Int => ((=> Nothing) => Nothing)
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your detailed explanation! It finally works! gist.github.com/shehaaz/7ea265d8b43006d7b395a035c3479925

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.