Apa itu Scala ?

Bahasa JVM yang memadukan pemrograman berorientasi objek dan fungsional dalam satu model yang terpadu.

Daftar isi

Scala adalah bahasa pemrograman yang berjalan di atas Java Virtual Machine (JVM) dan memadukan dua gaya pemrograman, yaitu berorientasi objek dan fungsional, dalam satu model yang terpadu. Topik ini membahas posisi Scala di ekosistem JVM, isi kedua paradigma tersebut, perbedaan antara Scala 3 dan Scala 2.13, serta pembeda utamanya dari Java. Di akhir topik, sebuah program kecil dijalankan untuk melihat kedua gaya itu bekerja berdampingan dalam satu berkas.

Bahasa di atas JVM#

JVM adalah mesin virtual yang membaca dan mengeksekusi bytecode, yaitu instruksi biner hasil kompilasi kode sumber. Java bukan satu-satunya bahasa yang memproduksi bytecode. Compiler Scala bernama scalac menerjemahkan kode Scala menjadi bytecode yang sama dengan bytecode yang dihasilkan javac untuk kode Java. Karena formatnya sama, pustaka Java dapat dipanggil langsung dari kode Scala tanpa lapisan perantara.

Diagram berikut menunjukkan alur tersebut. Kode Scala dan kode Java sama-sama berakhir sebagai bytecode, lalu dijalankan oleh JVM di berbagai sistem operasi.

Kode ScalaKode JavaBytecodeJVMscalacjavacberbagai sistem operasi
Kode Scala dan kode Java sama-sama dikompilasi menjadi bytecode yang dijalankan JVM

Posisi ini memberikan dua keuntungan. Pertama, kinerja program Scala setara dengan program Java karena keduanya berjalan pada runtime yang sama dan menerima pengoptimalan yang sama dari JVM, termasuk kompilasi just-in-time (JIT), yakni penerjemahan bytecode menjadi kode mesin saat program berjalan. Kedua, ekosistem pustaka Java yang besar dapat digunakan apa adanya, sehingga proyek Scala tidak memulai dari nol. Konsekuensinya, Scala menambahkan lapisan abstraksi di atas JVM, sehingga pesan error hasil kompilasi Scala kadang lebih sulit dibaca daripada pesan error Java.

Dua paradigma dalam satu bahasa#

Gaya berorientasi objek menyusun program dari objek, yaitu data beserta metode yang beroperasi pada data tersebut. Gaya fungsional menyusun program dari fungsi dan transformasi nilai tanpa mutasi. Scala tidak memilih salah satu, karena keduanya menjadi bagian inti bahasanya. Setiap nilai di Scala adalah objek, sehingga angka, string, hingga fungsi semuanya memiliki metode. Pada saat yang sama, fungsi adalah nilai yang dapat disimpan dalam val, diteruskan sebagai parameter, dan dikembalikan dari fungsi lain.

Perpaduan itu terlihat pada kebiasaan menulis kode Scala. Data dimodelkan sebagai tipe yang tidak berubah, sedangkan alur data dinyatakan sebagai rangkaian transformasi seperti map dan filter. Rangkaian semacam ini menekan jumlah keadaan yang berubah-ubah, sehingga program lebih mudah diuji dan dilacak perilakunya. Slogan resmi Scala di scala-lang.org, yaitu Object-Oriented Meets Functional, merangkum posisi tersebut: bukan dua dunia yang dijembatani, melainkan satu bahasa yang memang dirancang di atas keduanya.

Scala 3 dan Scala 2.13#

Versi bahasa Scala yang beredar saat ini terbagi dalam dua garis besar, yaitu Scala 3 dan Scala 2.13. Scala 3 dirilis pada tahun 2021 dan membawa penyederhanaan sintaks, salah satunya blok berbasis indentasi yang menggantikan banyak kurung kurawal. Scala 2.13 adalah garis versi sebelumnya yang masih dipelihara dan digunakan di banyak codebase, yaitu kumpulan kode sumber sebuah proyek.

Keduanya bukan dua bahasa yang asing satu sama lain. Panduan migrasi resmi menjelaskan hubungan Scala 3 dengan kode Scala 2, dan sebagian besar kode Scala 2.13 dapat dibaca ulang sebagai kode Scala 3 dengan penyesuaian kecil. Contoh codebase besar yang masih berjalan pada Scala 2.13 adalah Apache Spark. Rilis Spark 4.0 menjadikan Scala 2.13 satu-satunya target setelah Scala 2.12 ditinggalkan, sehingga kode Spark yang ditemui pembaca kemungkinan besar ditulis dengan Scala 2.13.

Jalur ini mengikuti garis Scala 3, dengan versi 3.9.0 sebagai default (pilihan bawaan) Scala CLI 1.18 pada lingkungan jalur ini.

Pembeda utama dari Java#

Scala dan Java berbagi runtime yang sama, tetapi keduanya berbeda dalam cara kode ditulis. Perbedaan yang paling terasa dirangkum dalam tabel berikut.

AspekJavaScala
Deklarasi nilaiTipe ditulis pada setiap deklarasival dan var dengan tipe yang disimpulkan compiler
Nilai yang berubahvar digunakan bebasval yang tidak berubah sebagai pilihan utama
FungsiHanya ada metode milik kelasFungsi adalah nilai yang dapat diteruskan
Percabanganif adalah pernyataanif dan match adalah ekspresi yang menghasilkan nilai

Inferensi tipe (type inference) adalah istilah pertama yang perlu dikenal. Compiler menentukan tipe dari bentuk nilainya, sehingga penulisan tipe eksplisit tidak diperlukan pada setiap baris.

scala Contoh: tipe yang disimpulkan compiler
val batas = 80      // compiler menyimpulkan Int
val nama = "Scala"  // compiler menyimpulkan String

Java modern mengadopsi sebagian ide yang sama, seperti lambda sejak Java 8, var sejak Java 10, dan record sejak Java 16. Perbedaan mendasarnya bukan pada keberadaan ide-ide itu, melainkan pada tempatnya dalam desain bahasa. Scala dirancang sejak awal di atas kedua paradigma, sehingga gaya fungsional bukan tambahan, melainkan pilihan bawaan.

Program pertama#

Perpaduan kedua paradigma paling mudah dilihat dari contoh yang berjalan. Buat berkas rekap-nilai.scala dengan isi berikut, lalu jalankan perintah scala-cli run rekap-nilai.scala. Perintah tersebut mengompilasi berkasnya dan menjalankan hasilnya dalam satu langkah.

scala rekap-nilai.scala
// Model data: case class memadukan data dan perilaku dalam satu tipe
case class Student(name: String, score: Int):
  def passed: Boolean =
    score >= 80

@main def summary(): Unit =
  val students = List(Student("Ali", 88), Student("Budi", 92), Student("Citra", 79))

  // Gaya fungsional: transformasi koleksi tanpa perulangan eksplisit
  val rataRata = students.map(_.score).sum / students.size
  val lulus = students.filter(_.passed).map(_.name)

  println(s"Jumlah siswa: ${students.size}")
  println(s"Rata-rata skor: $rataRata")
  println(s"Yang lulus: $lulus")
bash
scala-cli run rekap-nilai.scala
text Keluaran
Jumlah siswa: 3
Rata-rata skor: 86
Yang lulus: List(Ali, Budi)

Struktur programnya memperlihatkan kedua paradigma berdampingan. case class Student memodelkan data sebagai tipe yang tidak berubah beserta metode passed, yaitu bagian yang berorientasi objek. Baris students.map(_.score).sum dan students.filter(_.passed).map(_.name) menyatakan alur data sebagai rangkaian transformasi tanpa satu pun perulangan eksplisit, yaitu bagian yang fungsional. Penanda @main menjadikan fungsi summary titik masuk program, sehingga satu berkas ini dapat dijalankan tanpa proyek dan tanpa berkas konfigurasi.

Hasil 86 juga layak dicermati. Skor 88, 92, dan 79 berjumlah 259, lalu 259 dibagi 3 menghasilkan 86 tanpa bagian pecahan karena kedua sisinya bertipe Int. Perilaku pembagian bulat semacam ini dijelaskan lebih rinci pada pembahasan tipe angka.

Ringkasan#

  • Scala adalah bahasa di JVM yang memadukan pemrograman berorientasi objek dan fungsional, karena setiap nilai adalah objek dan setiap fungsi adalah nilai.
  • Kode Scala dikompilasi menjadi bytecode yang sama dengan kode Java, sehingga pustaka Java dipanggil langsung dan kinerjanya setara.
  • Scala 3 adalah garis versi terkini dengan blok berbasis indentasi, sedangkan banyak codebase produksi, termasuk Apache Spark, masih berjalan pada Scala 2.13.
  • Pembeda utamanya dari Java adalah tipe yang disimpulkan compiler, val yang tidak berubah sebagai pilihan utama, dan fungsi yang berkedudukan sebagai nilai.

Referensi#