What is the point of multiple parameter clauses in function definitions in Scala?
Asked Answered
F

5

9

I'm trying to understand the point of this language feature of multiple parameter clauses and why you would use it. Eg, what's the difference between these two functions really?

class WTF {
    def TwoParamClauses(x : Int)(y: Int) = x + y
    def OneParamClause(x: Int, y : Int) = x + y
}

>> val underTest = new WTF
>> underTest.TwoParamClauses(1)(1) // result is '2'
>> underTest.OneParamClause(1,1) // result is '2' 

There's something on this in the Scala specification at point 4.6. See if that makes any sense to you.

NB: the spec calls these 'parameter clauses', but I think some people may also call them 'parameter lists'.

Formally answered 2/9, 2011 at 4:44 Comment(5)
Nnon-scala programmer here. Maybe it's just a different style? Not everything has to only have one way of doing it.Bullhead
okay, there's a bit of an answer to this in Daniel Sobral's answer to #4697904Formally
the accepted answer here probably answers this question: (1) so you don't have to specify the type from the first param clause in the second clause; (2) for flexibility of library design; (3) to make currying easier: #4915527Formally
Okay, this is really bugging me. There are no explicit functions in the post -- only methods. A function is a first-class value, while a method is not. A method is "part" of an object and is what an object "knows how to respond to". A function is an object (of type FunctionN/PartialFunctionN) which has an apply method -- the apply method is not a function. This is important to keep in mind because the rules for methods and functions differ. For instance, functions cannot be overloaded and methods (without an implicit conversion to a function) cannot be passed as functions.Langlauf
@pst, Although I agree with the sentiment, I was surprised to learn that the Scala Language Spec (Section 4.6, function declarations) refers to methods as a specific kind of function. Maybe, to be precise, it's better to distinguish methods versus function objects.Uzbek
U
10

Here are three practical uses of multiple parameter lists,

  1. To aid type inference. This is especially useful when using higher order methods. Below, the type parameter A of g2 is inferred from the first parameter x, so the function arguments in the second parameter f can be elided,

    def g1[A](x: A, f: A => A) = f(x)
    g1(2, x => x) // error: missing parameter type for argument x
    
    def g2[A](x: A)(f: A => A) = f(x)
    g2(2) {x => x} // type is inferred; also, a nice syntax
    
  2. For implicit parameters. Only the last parameter list can be marked implicit, and a single parameter list cannot mix implicit and non-implicit parameters. The definition of g3 below requires two parameter lists,

    // analogous to a context bound: g3[A : Ordering](x: A)
    def g3[A](x: A)(implicit ev: Ordering[A]) {}
    
  3. To set default values based on previous parameters,

    def g4(x: Int, y: Int = 2*x) {} // error: not found value x
    def g5(x: Int)(y: Int = 2*x) {} // OK
    
Uzbek answered 2/9, 2011 at 18:2 Comment(0)
H
8

TwoParamClause involves two method invocations while the OneParamClause invokes the function method only once. I think the term you are looking for is currying. Among the many use cases, it helps you to breakdown the computation into small steps. This answer may convince you of usefulness of currying.

Hypothermia answered 2/9, 2011 at 5:24 Comment(4)
The form with two parameter clauses only invokes the method once -- the result of that invocation is a function which is then applied resulting in the final value.Langlauf
@pst: But applying a function also invokes a method (namely, the function's apply method).Wesleywesleyan
@Alexey Romanov True. The original post wording was different ;-) In the now-dated comment I was trying to emphasis the difference between a method (something an object knows how to "respond to") and a function (a discrete object that can be applied, even if such application is the result of invoking a method upon it). I also still disagree with the terminology "...invokes the function only once" because it invokes the OneParamClause method only once.Langlauf
I hope it is now technically correct. Sorry for any confusion. This blog covers the distinction between functions and methods very wellHypothermia
P
6

There is a difference between both versions concerning type inference. Consider

def f[A](a:A, aa:A) = null
f("x",1)
//Null = null

Here, the type A is bound to Any, which is a super type of String and Int. But:

def g[A](a:A)(aa:A) = null
g("x")(1)

error: type mismatch;
 found   : Int(1)
 required: java.lang.String
       g("x")(1)
              ^

As you see, the type checker only considers the first argument list, so A gets bound to String, so the Int value for aa in the second argument list is a type error.

Promise answered 2/9, 2011 at 8:10 Comment(0)
S
4

Multiple parameter lists can help scala type inference for more details see: Making the most of Scala's (extremely limited) type inference

Type information does not flow from left to right within an argument list, only from left to right across argument lists. So, even though Scala knows the types of the first two arguments ... that information does not flow to our anonymous function.

...

Now that our binary function is in a separate argument list, any type information from the previous argument lists is used to fill in the types for our function ... therefore we don't need to annotate our lambda's parameters.

Sensational answered 2/9, 2011 at 8:3 Comment(2)
Please make sure to include excerpts and/or reasoning and not just bare-links in posts. A very nice article-find, however.Langlauf
I thought my short description would be enough to tease and for complete reference one should read the blog. But this way it's fine too :)Sensational
S
3

There are some cases where this distinction matters:

  1. Multiple parameter lists allow you to have things like TwoParamClauses(2); which is automatically-generated function of type Int => Int which adds 2 to its argument. Of course you can define the same thing yourself using OneParamClause as well, but it will take more keystrokes

  2. If you have a function with implicit parameters which also has explicit parameters, implicit parameters must be all in their own parameter clause (this may seem as an arbitrary restriction but is actually quite sensible)

Other than that, I think, the difference is stylistic.

Selfhelp answered 2/9, 2011 at 5:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.