How to set default values for Scala method parameters

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 5.3, “How to set default values for Scala method parameters.”

Problem

You want to set default values for Scala method parameters so the method can optionally be called without those parameters having to be assigned.

Solution

Specify the default value for parameters in the method signature. In the following code, the timeout field is assigned a default value of 5000, and the protocol field is given a default value of http:

class Connection {
    def makeConnection(timeout: Int = 5000, protocol: String = "http") {
        println("timeout = %d, protocol = %s".format(timeout, protocol))
        // more code here
    }
}

This method can now be called in the following ways:

c.makeConnection()
c.makeConnection(2000)
c.makeConnection(3000, "https")

The results are demonstrated in the REPL:

scala> val c = new Connection
c: Connection = Connection@385db088

scala> c.makeConnection()
timeout = 5000, protocol = http

scala> c.makeConnection(2000)
timeout = 2000, protocol = http

scala> c.makeConnection(3000, "https")
timeout = 3000, protocol = https

Note that empty parentheses are used in the first example. Attempting to call this method without parentheses results in an error:

scala> c.makeConnection
<console>:10: error: missing arguments for method makeConnection in Connection;
follow this method with `_' to treat it as a partially applied function
              c.makeConnection
                ^

The reason for this error is discussed in Recipe 9.6, “Using Partially Applied Functions”. If you like to call methods with the names of the method parameters, the makeConnection method can also be called in these ways:

c.makeConnection(timeout=10000)
c.makeConnection(protocol="https")
c.makeConnection(timeout=10000, protocol="https")

Discussion

Just as with constructor parameters, you can provide default values for method arguments. Because you have provided defaults, the consumer of your method can either supply an argument to override the default or skip the argument, letting it use its default value.

Arguments are assigned from left to right, so the following call assigns no arguments and uses the default values for both timeout and protocol:

c.makeConnection()

This call sets timeout to 2000 and leaves protocol to its default:

c.makeConnection(2000)

This call sets both the timeout and protocol:

c.makeConnection(3000, "https")

Note that you can’t set the protocol only with this approach, but as shown in the Solution, you can use a named parameter:

c.makeConnection(protocol="https")

If your method provides a mix of some fields that offer default values and others that don’t, list the fields that have default values last. To demonstrate the problem, the following example assigns a default value to the first argument and does not assign a default to the second argument:

class Connection {
    // intentional error
    def makeConnection(timeout: Int = 5000, protocol: String) {
        println("timeout = %d, protocol = %s".format(timeout, protocol))
        // more code here
    }
}

This code compiles, but you won’t be able to take advantage of the default, as shown in the REPL errors:

scala> c.makeConnection(1000)
<console>:10: error: not enough arguments for method makeConnection:

(timeout: Int, protocol: String)Unit.
Unspecified value parameter protocol.
              c.makeConnection(1000)
                              ^

scala> c.makeConnection("https")
<console>:10: error: not enough arguments for method makeConnection:

(timeout: Int, protocol: String)Unit.
Unspecified value parameter protocol.
              c.makeConnection("https")
                              ^

By changing the method so the first field doesn’t have a default and the last field does, the default method call can now be used:

class Connection {
  // corrected implementation
  def makeConnection(timeout: Int, protocol: String = "http") {
    println("timeout = %d, protocol = %s".format(timeout, protocol))
    // more code here
  }
}

scala> c.makeConnection(1000)
timeout = 1000, protocol = http

scala> c.makeConnection(1000, "https")
timeout = 1000, protocol = https