0

Is it possible to combine variable arguments and default parameters in a Scala method function definition? Specifically, I'm trying to write a patch method with the following signature:

def patch(body: String, contentType: ContentType = ContentType.APPLICATION_JSON, customHeaders: (String, String)*)

I get the error Parameter section with *-parameter cannot have default arguments. So I assume it was a matter of ordering the parameters. However, I'm required to place *-parameters last.

My questions are:

  • Why does *-parameter have to be last? Is it so the compiler can easily parse the arguments?

  • Why can't *-parameter come after the default arguments? I imagine the same argument applies where it's easier for the compiler to parse arguments because default arguments and variable arguments are both optional.

1 Answer 1

3

Why does *-parameter have to be last?

Technically, even if the *-parameter isn't restricted to be the last, the compiler should be able to figure it out. This SO link offers some insight (albeit unofficial) into possible rationale.

Why can't *-parameter come after the default arguments?

If *-parameter after a default argument were allowed, there would be ambiguity in which argument variables should be assigned the supplied parameters in some cases. For example:

def foo(a: String = "hi", bs: String*) = a + " " + bs.mkString(" ")

foo("hello", "world")  // Should "hello" go to `a` or be a part of `bs`?

Note that technically this restriction could also be lifted, say, by requiring explicit argument variable assignment in cases when ambiguity arises (e.g. foo(a="hello", "world")).

To circumvent the restriction, you can resort to currying (which allows you to have a *-parameter per argument list):

def bar(s: String, i: Int = 1, ts: (String, String)*) =
  ts.map(t => (t._1 + s*i, t._1 + s*i))
// <console>:23: error: a parameter section with a `*'-parameter is not allowed to have default arguments
//        def bar(s: String, i: Int = 1, ts: (String, String)*) = {

def bar(s: String, i: Int = 1)(ts: (String, String)*) =
  ts.map(t => (t._1 + s*i, t._2 + s*i))

bar("!", 2)(("a", "b"), ("c", "d"))
// res1: Seq[(String, String)] = ArrayBuffer((a!!,b!!), (c!!,d!!))
Sign up to request clarification or add additional context in comments.

2 Comments

"If *-parameter after a default argument were allowed, there would be ambiguity in which argument variables should be assigned the supplied parameters in some cases." – Not really. It is pretty simple to come up with easy-to-understand rules to disambiguate. It is simply a design choice.
@Jörg W Mittag, I think you're right. Among other reasons, the design choice could be based on that the decision of "*-parameter must be the last" was made and the fact that default arguments are more practically useful to be placed last. I've added a relevant note in the answer.

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.