How do you manage state and side effects in functional programming with Scala?
Instruction: Discuss strategies for managing state and handling side effects in a functional programming paradigm using Scala.
Updated
Model state transitions as functions that return a new state and a description of intended actions. Keep interpreting those actions at a boundary responsible for I/O, failure handling and resource management.
final case class Stock(available: BigInt)
final case class Reserved(quantity: BigInt)
def reserve(stock: Stock, quantity: BigInt)
: Either[String, (Stock, List[Reserved])] =
if (stock.available < 0) Left("Invalid stock")
else if (quantity <= 0) Left("Quantity must be positive")
else if (quantity > stock.available) Left("Insufficient stock")
else Right((Stock(stock.available - quantity), List(Reserved(quantity))))
@main def stateExample(): Unit = {
val initial = Stock(10)
assert(reserve(initial, 3) == Right((Stock(7), List(Reserved(3)))))
assert(reserve(initial, 11) == Left("Insufficient stock"))
assert(initial == Stock(10))
}
No database update or notification occurs here. A separate interpreter decides how to persist the transition and process the action. With concurrent writers, the persistence boundary still needs a transaction, version check or equivalent coordination; retries may require idempotency. Pure calculations alone do not prevent lost updates. Pure functions and effects
Distinguish error and effect abstractions. Option represents absence; Try evaluates its by-name computation when constructed and captures nonfatal exceptions; Future.apply schedules work when called. They are not all deferred, repeatable descriptions of effects. Libraries such as Cats Effect provide IO.delay to describe suspended work and a runtime to execute it. That is a library capability, not an automatic property of Scala expressions. Try implementation Futures Cats Effect IO
Local mutation can be appropriate inside a controlled implementation. Shared state needs an explicit ownership and concurrency policy; cancellation, cleanup and durability need their own design.