In pure functional programming, only immutable values are used. In Scala this means:
- All variables are created as
val
fields - Only immutable collections classes are used, such as
List
,Vector
, and the immutableMap
andSet
classes
Using only immutable variables raises an interesting question: If everything is immutable, how does anything ever change?
When it comes to using collections, one answer is that you don’t mutate an existing collection; instead, you apply a function to an existing collection to create a new collection.
This is where higher-order functions like map
and filter
come in.
For example, imagine that you have a list of names—a List[String]
—that are all in lowercase, and you want to find all the names that begin with the letter "j"
, and then you want to capitalize those names.
In FP you write this code:
val a = List("jane", "jon", "mary", "joe")
val b = a.filter(_.startsWith("j"))
.map(_.capitalize)
As shown, you don’t mutate the original list a
.
Instead, you apply filtering and transformation functions to a
to create a new collection, and assign that result to the new immutable variable b
.
Similarly, in FP you don’t create classes with mutable var
constructor parameters.
That is, you don’t write this:
// don’t do this in FP
class Person(var firstName: String, var lastName: String)
--- ---
Instead, you typically create case
classes, whose constructor parameters are val
by default:
case class Person(firstName: String, lastName: String)
Now you create a Person
instance as a val
field:
val reginald = Person("Reginald", "Dwight")
Then, when you need to make a change to the data, you use the copy
method that comes with a case
class to “update the data as you make a copy,” like this:
val elton = reginald.copy(
firstName = "Elton", // update the first name
lastName = "John" // update the last name
)
There are other techniques for working with immutable collections and variables, but hopefully these examples give you a taste of the techniques.
Depending on your needs, you may create enums, traits, or classes instead of
case
classes. See the Data Modeling chapter for more details.
Contributors to this page:
Contents
- Introduction
- Scala Features
- Why Scala 3?
- A Taste of Scala
- Hello, World!
- The REPL
- Variables and Data Types
- Control Structures
- Domain Modeling
- Methods
- First-Class Functions
- Singleton Objects
- Collections
- Contextual Abstractions
- Toplevel Definitions
- Summary
- A First Look at Types
- String Interpolation
- Control Structures
- Domain Modeling
- Tools
- OOP Modeling
- FP Modeling
- Methods
- Method Features
- Main Methods in Scala 3
- Summary
- Functions
- Anonymous Functions
- Function Variables
- Eta-Expansion
- Higher-Order Functions
- Write Your Own map Method
- Creating a Method That Returns a Function
- Summary
- Packaging and Imports
- Scala Collections
- Collections Types
- Collections Methods
- Summary
- Functional Programming
- What is Functional Programming?
- Immutable Values
- Pure Functions
- Functions Are Values
- Functional Error Handling
- Summary
- Types and the Type System
- Inferred Types
- Generics
- Intersection Types
- Union Types
- Algebraic Data Types
- Variance
- Opaque Types
- Structural Types
- Dependent Function Types
- Other Types
- Contextual Abstractions
- Extension Methods
- Context Parameters
- Context Bounds
- Given Imports
- Type Classes
- Multiversal Equality
- Implicit Conversions
- Summary
- Concurrency
- Scala Tools
- Building and Testing Scala Projects with sbt
- Worksheets
- Interacting with Java
- Scala for Java Developers
- Scala for JavaScript Developers
- Scala for Python Developers
- Where To Go Next