Membongkar arsitektur Scala: bagaimana scalac mengkompilasi source code menjadi bytecode JVM, peran scala runner, REPL, dan format TASTy dalam interoperabilitas antar versi, serta dukungan lintas platform lewat Scala.js dan Scala Native.

Setelah di episode 1 kita memahami sejarah dan filosofi "scalable" di balik Scala, pada episode ini kita membedah mesin di balik bahasa ini: bagaimana sebuah file .scala menjadi program yang berjalan. Memahami arsitektur ini bukan sekadar pengetahuan akademis — ia menentukan cara kalian debugging, memilih tool, dan menilai kinerja program Scala di produksi.
Mengapa arsitektur penting? Karena banyak misteri Scala — kenapa startup-nya agak lambat, kenapa library Java bisa dipakai langsung, kenapa ada file .tasty di classpath — semuanya terjawab oleh satu fakta dasar: Scala dikompilasi menjadi bytecode JVM. Dari fakta tunggal ini, hampir semua perilaku tooling Scala bisa dijelaskan.
Compiler Scala (scalac) bekerja dalam beberapa tahap. Simplifikasinya begini:
scalac mem-parse source code menjadi AST (Abstract Syntax Tree)..class.Konsekuensi paling penting: library Java apa pun bisa dipakai langsung dari Scala, dan sebaliknya. Kalian menulis Scala, tetapi berbagi classpath dan runtime yang sama dengan Java. Ini adalah salah satu alasan terbesar Scala tetap relevan — ia mewarisi seluruh ekosistem JVM yang sudah matang.
import java.time.LocalDate
val today = LocalDate.now()
println(today)LocalDate adalah class Java murni — tanpa adapter, tanpa bridge, langsung bekerja.
Arsitektur Scala tidak hanya scalac. Ada beberapa komponen yang saling melengkapi:
| Komponen | Peran |
|---|---|
scalac | Compiler — mengubah .scala menjadi bytecode |
scala runner | Menjalankan program dan REPL (Scala CLI default sejak 3.5) |
| REPL | Shell interaktif untuk eksperimen cepat |
| sbt / Mill / Scala CLI | Build tool & dependency management |
| TASTy | Format tipe antar versi — interoperabilitas 2 → 3 |
Sejak Scala 3.5, scala adalah front-end default untuk menjalankan kode — menggantikan peran terpisah antara scala runner lama dan scala-cli. Di Scala 3.8, REPL dipisah menjadi artifact tersendiri (scala3-repl) agar kompilasi inti lebih ringan:
scalascala> val x = 1 + 2
val x: Int = 3
scala> x * 2
val res0: Int = 6
scala> :quitREPL adalah teman terbaik untuk mempelajari bahasa: ketik ekspresi, lihat tipe hasilnya, ulangi. Di series ini kita sering menggunakannya untuk demonstrasi cepat.
TASTy (Typed Abstract Syntax Trees) adalah format file yang dihasilkan scalac di samping bytecode. Fungsinya: menyimpan informasi tipe lengkap hasil type-checking sehingga kompiler versi lebih baru bisa membaca kode yang dikompilasi versi lama — khususnya memungkinkan Scala 3 memakai library Scala 2.
scalac hello.scala
ls *.class *.tastyIni menjawab misteri "kenapa ada dua macam file": .class untuk JVM, .tasty untuk compiler. Java hanya melihat .class; scalac memakai .tasty untuk type inference yang akurat.
JVM bukan satu-satunya target Scala. Arsitektur Scala 3 mendukung tiga backend sekaligus:
| Backend | Target | Kasus pakai |
|---|---|---|
| JVM | Bytecode JVM | Backend service, data pipeline (default series ini) |
| Scala.js | JavaScript | Frontend, berbagi logic antara client dan server |
| Scala Native | Binary native | Aplikasi dengan startup cepat & footprint kecil |
Dengan Scala.js, kode domain yang sama bisa dipakai di server (JVM) dan browser — pola ini populer di project full-stack. Scala Native menargetkan binary tanpa JVM, cocok untuk CLI tools dan aplikasi embedded. Ketiganya dikompilasi dari source yang sama, meski dengan karakteristik runtime berbeda.
Note
Untuk series ini kita fokus penuh di backend JVM — itu target paling umum dan tempat ekosistem tooling (sbt, Metals, Spark, Kafka) paling matang. Konsep bahasa yang kalian pelajari berlaku sama untuk semua backend.
Arsitektur ini membentuk alur kerja harian kalian. Saat menggunakan Metals, alurnya terotomasi, tetapi penting memahami lapisannya:
Metals memanggil scalac secara incremental (hanya file yang berubah) sehingga error muncul detik demi detik, bukan menit. Ini dimungkinkan karena format TASTy dan incremental compiler yang menjadi fondasi tooling Scala modern.
Beberapa kesalahan pemahaman yang sering terjadi:
Inti yang harus dibawa pulang:
scalac menjadi bytecode JVM — inilah akar interoperabilitas dengan Java.scala runner dan REPL adalah teman belajar terbaik; REPL dipisah ke artifact scala3-repl di 3.8.Di episode 3 selanjutnya, kita masuk praktik pertama yang sesungguhnya: instalasi dan Hello World — verifikasi ulang toolchain, menulis program pertama dengan @main, menjalankannya lewat scala run, dan mengenal struktur program minimal Scala. Sampai jumpa di episode 3!