Scala Named Arguments
Named arguments let you call a function by specifying which parameter each value belongs to, using the parameter's name. Instead of relying on position, you write paramName = value. This eliminates confusion when a function has many parameters of the same type and makes call sites easier to read.
Basic Named Argument Syntax
def createAccount(username: String, email: String, age: Int, active: Boolean): Unit =
println(s"$username | $email | age=$age | active=$active")
// Positional call — order matters
createAccount("alice", "alice@example.com", 28, true)
// Named call — order does not matter
createAccount(
age = 28,
email = "alice@example.com",
username = "alice",
active = true
)
Both calls produce identical results. Named arguments free you from memorizing parameter order.
The Problem They Solve
// Which Boolean is which? Is 5 a limit or a timeout?
connect("localhost", 5432, "mydb", true, false, 5)
// Crystal clear with named arguments
connect(
host = "localhost",
port = 5432,
database = "mydb",
ssl = true,
logging = false,
timeout = 5
)
The positional call is a puzzle. The named call reads like a configuration file — no guessing required.
Mixed: Positional and Named
def order(product: String, quantity: Int, price: Double, express: Boolean = false): Unit =
println(s"$product x$quantity @ ₹$price | express=$express")
// First two positional, rest named
order("Laptop", 1, price = 75000.0, express = true)
// Rule: once you use a named argument, all following must also be named
// order("Laptop", quantity = 1, 75000.0) // Error: positional after named
order("Laptop", quantity = 1, price = 75000.0) // OK
Named Arguments with Default Parameters
Named arguments combine powerfully with default parameters. You can skip any default parameter and supply only the ones you want to override, regardless of position:
def sendNotification(
userId: Int,
message: String,
channel: String = "email",
priority: String = "normal",
retries: Int = 3,
sound: Boolean = true
): Unit =
println(s"User $userId: '$message' via $channel | priority=$priority")
// Skip 'channel', 'priority', 'retries' — only override 'sound'
sendNotification(userId = 42, message = "Your order shipped!", sound = false)
// User 42: 'Your order shipped!' via email | priority=normal
// Skip to a specific parameter by name
sendNotification(42, "Flash sale!", priority = "high")
// User 42: 'Flash sale!' via email | priority=high
Improving Readability in Long Calls
// Hard to read — what is each value?
val chart = BarChart(800, 600, true, false, "Sales Q4", 12, "#336699", 14)
// Easy to read — self-documenting
val chart = BarChart(
width = 800,
height = 600,
showGrid = true,
showLegend = false,
title = "Sales Q4",
barCount = 12,
barColor = "#336699",
fontSize = 14
)
Named Arguments with Case Classes
case class ServerConfig(
host: String,
port: Int,
maxConnections: Int = 100,
readTimeoutMs: Int = 3000,
writeTimeoutMs: Int = 3000,
ssl: Boolean = false
)
// Only specify what differs from defaults
val devServer = ServerConfig(
host = "localhost",
port = 8080
)
val prodServer = ServerConfig(
host = "prod.api.com",
port = 443,
ssl = true,
maxConnections = 500,
readTimeoutMs = 10000
)
println(devServer)
// ServerConfig(localhost,8080,100,3000,3000,false)
println(prodServer)
// ServerConfig(prod.api.com,443,500,10000,3000,true)
Named Arguments in copy
Case class copy always uses named arguments — this shows how natural the pattern is:
case class Employee(name: String, dept: String, salary: Double, remote: Boolean)
val emp1 = Employee("Vikram", "Engineering", 80000.0, false)
// Copy with specific changes — named arguments make it obvious
val emp2 = emp1.copy(dept = "Architecture", salary = 95000.0)
val emp3 = emp1.copy(remote = true)
println(emp2) // Employee(Vikram,Architecture,95000.0,false)
println(emp3) // Employee(Vikram,Engineering,80000.0,true)
Avoiding Boolean Confusion
Multiple boolean parameters are the most common place where named arguments prevent bugs:
def setPermissions(
canRead: Boolean,
canWrite: Boolean,
canDelete: Boolean,
canShare: Boolean
): Unit =
println(s"read=$canRead write=$canWrite delete=$canDelete share=$canShare")
// Which Boolean is for what? Easy to swap accidentally:
setPermissions(true, false, false, true) // unclear
// Named: intent is obvious, order cannot be swapped accidentally:
setPermissions(
canRead = true,
canWrite = false,
canDelete = false,
canShare = true
)
Named Arguments Do Not Affect Performance
Named arguments are resolved at compile time. The compiler maps each named argument to its correct position in the function signature before generating bytecode. At runtime, there is no overhead compared to positional calls.
When to Use Named Arguments
Always use named args when:
✓ Function has 3+ parameters of the same type (e.g., multiple Booleans)
✓ Skipping default parameters out of order
✓ The call site is a public API others will read
✓ Parameter names add clarity (like configuration)
Skip named args when:
✗ Function has 1-2 obvious parameters (e.g., add(a, b))
✗ Parameter names are generic (i, x, n) and context is clear
✗ Performance-critical tight loops (no overhead, but mental overhead)
Named arguments are a zero-cost documentation feature. They make call sites self-explanatory without adding runtime overhead, extra classes, or helper objects. Use them freely for any function where the parameter purpose might not be obvious from the value alone.
