Menguasai match expression di Scala 3 — wildcard, guards, dan destructuring — lalu memodelkan domain dengan Algebraic Data Type memakai enum dan case class, plus perbandingannya dengan sealed trait gaya Scala 2.

Setelah di episode 6 kalian mahir memanipulasi collections, sekarang kita memakai senjata paling khas Scala: pattern matching. Jika map/filter adalah kata kerja transformasi, maka match adalah mekanisme pengambilan keputusan — tetapi jauh lebih kuat daripada if/else atau switch di bahasa lain.
Mengapa episode ini penting? Karena pattern matching adalah jembatan antara type system dan logika bisnis. Kalian sudah punya tipe (Option, Either, enum); sekarang saatnya belajar "membuka" tipe tersebut secara aman dan ekspresif. Bersama ADT, ini adalah pola yang paling sering membedakan kode Scala yang bagus dari yang sekadar bisa berjalan.
match di Scala 3 adalah ekspresi — ia menghasilkan nilai, bukan sekadar percabangan:
def describe(n: Int): String = n match
case 0 => "nol"
case 1 => "satu"
case 2 => "dua"
case _ => "angka lain"Perhatikan: hasil match langsung menjadi nilai return. Setiap case memeriksa pola; pola _ adalah wildcard yang mencocokkan apa saja.
match bekerja pada ekspresi apa pun, bukan hanya angka:
def score(s: Any): String = s match
case i: Int => s"int $i"
case s: String => s"string $s"
case _ => "lainnya"Ini type test ala Scala — mirip instanceof, tetapi dengan pengaman tipe di dalam setiap cabang.
Wildcard _ menangkap semua yang tidak cocok. Tempatkan di akhir, karena pola dievaluasi berurutan:
def classify(n: Int): String = n match
case 0 => "nol"
case n if n < 0 => "negatif"
case _ => "positif"Guard adalah if yang menempel pada pola — pola hanya cocok jika kondisinya terpenuhi:
def ageGroup(age: Int): String = age match
case a if a < 13 => "anak-anak"
case a if a < 20 => "remaja"
case a if a < 60 => "dewasa"
case _ => "lansia"Guard sangat berguna untuk rentang nilai, sementara pola murni lebih cocok untuk nilai/tipe spesifik.
Pola bisa mengikat nilai dan membongkar struktur:
def describePerson(p: (String, Int)): String = p match
case (name, age) if age >= 17 => s"$name sudah dewasa"
case (name, age) => s"$name masih muda ($age)"case class Point(x: Int, y: Int)
def quadrant(p: Point): String = p match
case Point(0, 0) => "pusat"
case Point(x, y) if x > 0 && y > 0 => "kanan-atas"
case Point(_, _) => "kuadran lain"Compiler memeriksa ekshaustivitas: jika kalian melupakan satu pola (misal Point(0, 0)), Scala memberi peringatan match may not be exhaustive — penjaga yang jarang ada di bahasa lain.
Pattern matching adalah cara idiomatis membuka container seperti Option:
def greetUser(maybeName: Option[String]): String = maybeName match
case Some(name) => s"Hello, $name!"
case None => "Hello, tamu!"def handleResult(r: Either[String, Int]): String = r match
case Right(v) => s"sukses: $v"
case Left(e) => s"gagal: $e"Pola Some(x) dan Right(v) "membongkar" isi container. Perhatikan bahwa kalian wajib menangani None/Left — compiler memaksa kalian berpikir tentang semua kemungkinan.
ADT adalah teknik memodelkan domain sebagai "sebuah nilai adalah salah satu dari sekumpulan bentuk yang mungkin". Dua bahan dasarnya:
enum di Scala 3.case class.Contoh klasik: memodelkan pembayaran di e-commerce.
enum Payment:
case Cash
case Card(brand: String, last4: String)
case Transfer(bank: String, ref: String)def process(p: Payment): String = p match
case Payment.Cash => "bayar tunai di kasir"
case Payment.Card(brand, last4) => s"kartu $brand ••••$last4"
case Payment.Transfer(bank, ref) => s"transfer $bank ref $ref"Jika nanti kalian menambah Payment.QrCode, compiler langsung berteriak di semua match yang lupa menangani varian baru. Inilah kekuatan ADT: perubahan domain tercermin sebagai error kompilasi, bukan bug runtime.
Sebelum Scala 3, ADT dibangun dengan sealed trait + case class:
sealed trait Shape
case class Circle(r: Double) extends Shape
case class Rect(w: Double, h: Double) extends Shapesealed membatasi extension hanya di file yang sama, sehingga compiler tahu semua kemungkinan dan bisa memeriksa ekshaustivitas. Gaya ini masih banyak ditemui di codebase produksi, dan sekarang bisa ditulis lebih ringkas sebagai enum:
enum Shape:
case Circle(r: Double)
case Rect(w: Double, h: Double)def area(s: Shape): Double = s match
case Shape.Circle(r) => Math.PI * r * r
case Shape.Rect(w, h) => w * hNote
Kapan memakai enum vs sealed trait? Untuk ADT baru, gunakan enum — sintaks Scala 3 yang lebih ringkas dan otomatis menyediakan method standar. sealed trait tetap relevan saat membaca/migrasi kode lama atau memerlukan perilaku inheritance yang rumit.
case _ berlebihan — di match pada enum, wildcard menyembunyikan varian baru yang lupa ditangani; lebih baik biarkan compiler memperingatkan.match untuk meniru switch imperative — di Scala, match menghasilkan nilai dan harus dimanfaatkan sebagai ekspresi.Inti yang harus dibawa pulang:
match adalah ekspresi yang menghasilkan nilai, dengan pola berurutan dan wildcard _.if) menambah syarat pada pola; destructuring membuka tuple dan case class.Option/Either diolah dengan pola Some/None/Right/Left — aman dan ekshaustif.enum) + product type (case class); perubahan domain terlihat sebagai error kompilasi.sealed trait adalah gaya Scala 2 yang masih umum di codebase produksi.Di episode 8 selanjutnya, kita beralih ke sisi object-oriented Scala: class, trait, dan object — konstruktor dan parameter val/var, inheritance, mixin dengan trait, serta singleton dan companion object. Sampai jumpa di episode 8!