Scalable Language. It interops seamlessly with Java.
When to Use
- Big Data Distributed Processing: Apache Spark, Apache Flink, and large-scale data engineering pipelines.
- High-Concurrency Reactive Systems: Building resilient distributed services with Akka/Pekko actors or Cats Effect/ZIO.
- Type-Level & Purely Functional Programming: Enforcing compile-time domain guarantees with Scala 3 given/using and opaque types.
- Enterprise JVM Microservices: Leveraging the entire Java ecosystem while utilizing concise, expressive FP idioms.
Quick Start
object Hello extends App {
println("Hello, World!")
val list = List(1, 2, 3) val doubled = list.map(_ * 2) println(doubled) }
## Core Concepts
### Scala 3 Contextual Abstractions: Given & Using
Type classes and dependency injection unified cleanly without implicit conversions:
```scala
// Define type class
trait JsonEncoder[A]:
def encode(a: A): String
// Given instances (type class implementations)
given JsonEncoder[String] with
def encode(a: String): String = s"\"${a.replace(""", "\\"")}\""
given JsonEncoder[Int] with
def encode(a: Int): String = a.toString
// Contextual function with 'using' clause
def toJson[T](value: T)(using encoder: JsonEncoder[T]): String =
encoder.encode(value)
// Extension methods for clean syntax
extension [T](value: T)(using encoder: JsonEncoder[T])
def asJson: String = encoder.encode(value)
Algebraic Data Types & Exhaustive Pattern Matching
Modeling domain states with Scala 3 sealed traits and enums:
enum PaymentStatus:
case Pending
case Authorized(transactionId: String, amountCents: Long)
case Failed(reason: String, retryable: Boolean)
def evaluatePayment(status: PaymentStatus): String = status match
case PaymentStatus.Pending =>
"Waiting for gateway response..."
case PaymentStatus.Authorized(txId, amt) =>
s"Payment $txId confirmed for \$${amt / 100.0}"
case PaymentStatus.Failed(reason, true) =>
s"Transient error: $reason. Retrying..."
case PaymentStatus.Failed(reason, false) =>
s"Permanent failure: $reason. Contacting customer."
Asynchronous Effect Management with Cats Effect
Pure functional concurrency with resource safety and fiber cancellation:
import cats.effect.{IO, IOApp, Resource}
import scala.concurrent.duration.*
object ServerApp extends IOApp.Simple:
def acquireDbConnection: IO[String] = IO.println("DB Connected") *> IO.pure("conn-123")
def releaseDbConnection(conn: String): IO[Unit] = IO.println(s"DB Disconnected: $conn")
val dbResource: Resource[IO, String] =
Resource.make(acquireDbConnection)(releaseDbConnection)
def run: IO[Unit] =
dbResource.use { conn =>
for
fiber <- IO.sleep(100.millis).as("Query result").start
res <- fiber.joinWithNever
_ <- IO.println(s"Executed on $conn: $res")
yield ()
}
Common Patterns
Enum and Pattern Matching in Scala 3
Problem: Verbose sealed trait hierarchies for algebraic data types in legacy Scala 2.
Solution:
Use Scala 3 concise enum definitions:
enum TransactionStatus:
case Pending
case Approved(txId: String, amount: BigDecimal)
case Rejected(reason: String)
def describe(status: TransactionStatus): String = status match
case TransactionStatus.Pending => "Transaction is being processed"
case TransactionStatus.Approved(id, amount) => s"Approved $id: $$$amount"
case TransactionStatus.Rejected(reason) => s"Declined: $reason"
Best Practices
Do:
- Embrace Scala 3 syntax: use
enum,given/using, and top-level definitions instead of Scala 2 package objects. - Use
opaque typealiases for type-safe domain identifiers (e.g.UserId,OrderId) without heap allocation overhead. - Structure async applications around functional effect systems (
Cats Effect 3orZIO 2) rather than rawscala.concurrent.Future. - Enable compiler strictness (
-Xfatal-warnings,-Wunused:all) to maintain clean codebases.
Don't:
- Use
varor mutable collections in domain logic; use immutable collections andcase class .copy(). - Catch raw
Throwablewithout re-throwing non-fatal exceptions; usescala.util.control.NonFatal. - Use
Option.getorTry.get; usegetOrElse, pattern matching, or for-comprehensions.
Troubleshooting
| Error | Cause | Solution |
|---|---|---|
type mismatch: found ... required ... |
Incompatible types in expression or missing implicit conversion. | Verify types and import appropriate typeclass instances. |
No implicit arguments found of type ... |
Missing using / implicit parameter in scope (e.g. ExecutionContext). |
Import default execution context: import scala.concurrent.ExecutionContext.Implicits.global. |
OutOfMemoryError during sbt compile |
JVM heap limit too low for Scala compiler. | Increase heap in .sbtopts: -J-Xmx4G. |