What Is an Anonymous Function?
An anonymous function, or lambda, is a function value written inline without being given a name via def - its full syntax is (parameters) => expression, such as (x: Int) => x + 1, and it is typically used exactly once, right where it's needed, most often as an argument to a higher-order function like map or filter. Unlike a def, which declares a method, a lambda expression is itself a value of type FunctionN (e.g., Function1[Int, Int]) that can be stored in a val, passed around, or invoked immediately, which is what makes it interchangeable with any other function value in Scala's type system.
Cricket analogy: A last-minute net bowler brought in for just one throwdown session, never given a squad number or a permanent role, is like a Scala lambda - used once inline for a specific job without being named like a regular squad member (a def).
Lambda Syntax Variations
When the parameter type can be inferred from context - such as inside list.map(...) where Scala already knows the list's element type - you can drop the explicit type annotation and even the parentheses for a single untyped parameter, writing list.map(x => x * 2) instead of list.map((x: Int) => x * 2). Scala also offers a terser underscore placeholder syntax for simple, single-use expressions: list.map(_ * 2) is equivalent to list.map(x => x * 2), where each underscore represents one positional argument, though this shorthand becomes confusing and should be avoided once an expression needs to reference the same parameter more than once or has multiple parameters with unclear roles.
Cricket analogy: Just as commentators shorten 'Mahendra Singh Dhoni' to simply 'MSD' once everyone already knows who's meant, Scala lets you drop (x: Int) => down to just x => - or even _ - once the parameter type is already known from context.
val nums = List(1, 2, 3, 4)
val doubledFull = nums.map((x: Int) => x * 2)
val doubledShort = nums.map(x => x * 2)
val doubledUnderscore = nums.map(_ * 2)
// all three produce List(2, 4, 6, 8)
val pairSum = List((1, 2), (3, 4)).map { case (a, b) => a + b }
// List(3, 7)Using Lambdas with Collections
Lambdas are the primary way to customize collection operations without writing a separate named method for every one-off transformation: sortBy(_.age) sorts by a derived key, exists(_ > 100) checks for at least one matching element, and reduce((a, b) => if (a > b) a else b) finds a maximum without importing a utility function. Because lambdas are lightweight, idiomatic Scala tends to favor many small, inline lambdas over verbose loops, which keeps the transformation logic co-located with the operation it customizes and avoids naming trivial one-off helper functions that would only ever be called once.
Cricket analogy: Sorting a squad list by strike rate with players.sortBy(_.strikeRate) is like a team analyst ranking players by one specific stat on demand, without writing a whole separate ranking program for every possible stat.
case class Employee(name: String, age: Int, salary: Double)
val employees = List(
Employee("Asha", 34, 95000),
Employee("Ravi", 29, 78000),
Employee("Meera", 41, 110000)
)
val sortedByAge = employees.sortBy(_.age)
val highEarners = employees.filter(_.salary > 80000)
val totalPayroll = employees.map(_.salary).sumClosures: Capturing Variables from the Enclosing Scope
A lambda that references a variable defined outside its own parameter list - such as val threshold = 100; nums.filter(x => x > threshold) - is called a closure, because it 'closes over' threshold from the enclosing scope and keeps a live reference to it rather than a frozen copy. If the captured variable is a mutable var, later changes to it are visible inside the closure the next time it runs, which is powerful for building stateful counters or accumulators but can also introduce subtle bugs if a closure escapes its original context and is called after the captured variable has changed unexpectedly.
Cricket analogy: A fielding captain who sets a mental 'boundary count' threshold and adjusts fielders dynamically as that count changes during the innings is like a closure capturing a mutable var - the fielding logic sees the live, updated count, not a frozen snapshot from when it was first set.
The underscore shorthand (_ * 2) is Scala's most concise lambda form but only works when each parameter is used exactly once, in the order it appears - for anything more complex, such as x => x * x + 1, spell out the parameter name for clarity.
Closures that capture a mutable var can cause confusing bugs in concurrent or delayed-execution code - for example, a lambda stored and invoked later inside a Future may see a different value of the captured variable than what it appeared to have when the lambda was written, since the reference is live, not a snapshot.
- An anonymous function (lambda) is a function value written inline without a def name, using (params) => expression syntax.
- Scala can infer lambda parameter types from context, letting you drop explicit type annotations.
- The underscore shorthand (_ * 2) represents positional parameters for simple, single-use expressions only.
- Lambdas are the primary way to customize collection operations like sortBy, exists, filter, and reduce inline.
- A closure is a lambda that captures a variable from its enclosing scope and keeps a live reference to it.
- Closures over mutable vars see the variable's current value at call time, not a frozen snapshot.
- Closures escaping into async code like Future can produce surprising results if captured mutable state changes later.
Practice what you learned
1. What is the correct syntax for a Scala anonymous function taking an Int and returning it doubled?
2. What does `list.map(_ * 2)` mean?
3. When should you avoid the underscore shorthand in a lambda?
4. What is a closure in Scala?
5. Why can closures capturing a mutable var be risky in asynchronous code like a Future?
Was this page helpful?
You May Also Like
Higher-Order Functions
Learn how Scala functions that accept or return other functions enable powerful, reusable abstractions like map, filter, fold, and currying.
Functions in Scala
Learn how to define, call, and structure functions in Scala using def, including default parameters, named arguments, and multiple parameter lists.
Conditionals and Match Expressions
Understand how Scala treats if-else and match as expressions that return values, including pattern matching on case classes and sealed traits.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics