- JEP 401: Value Classes and Objects telah mencapai tahap masuk sebagai preview JDK yang nyata
- Tujuan utamanya adalah membuat objek Java “dikodekan seperti class dan bekerja seperti int” sehingga mengurangi biaya header objek, alokasi heap, GC, dan indireksi pointer
- Value class di JDK 28 masih berupa tipe referensi yang bisa bernilai null; tipe non-null, generic terspesialisasi, dan encoding 128-bit belum disertakan, serta memerlukan
--enable-preview
- JVM dapat menskalarkan value object atau melakukan perataan heap pada field dan array, tetapi pada tipe induk seperti erased generic atau
Object, objek bisa dimaterialisasi sebagai objek heap
- Pengembang Java perlu mencerminkan perbedaan antara identity dan value dalam desain kode, dan dampaknya meluas ke
==, synchronized, primitive wrapper, performa array, hingga spesialisasi generic di masa depan
Cakupan Valhalla yang masuk ke JDK 28
- Pada 15 Juni, insinyur Oracle Lois Foltan mengonfirmasi integrasi JEP 401: Value Classes and Objects ke repositori utama OpenJDK dan target JDK 28
- Pull request terkait menambahkan lebih dari 197 ribu baris di 1.816 file
- Karena skala perubahannya besar, saat integrasi sempat ada permintaan kepada committer lain untuk menahan sementara commit besar
- JEP 401 adalah fitur preview yang dinonaktifkan secara default
- Untuk memakai sintaksnya, diperlukan
--enable-preview
- Brian Goetz menegaskan ini sebagai “bagian pertama dari Valhalla”
- JDK 28 dijadwalkan rilis pada Maret 2027, dan integrasi ke mainline direncanakan sekitar Juli 2026
Biaya model objek Java yang dibidik Valhalla
- Slogan Valhalla adalah “codes like a class, works like an int”
- Tujuannya adalah tetap memakai class biasa dengan method, validasi konstruktor, dan nama field yang bermakna, sambil memungkinkan JVM menanganinya seefisien primitive
- Di Java, selain 8 primitive, hampir semua adalah tipe referensi
- Pada
Point p = new Point(1, 2), p bukan point itu sendiri melainkan pointer yang menunjuk ke objek di heap
- Setiap kali field dibaca, JVM harus mengikuti pointer tersebut
- Saat jumlah objek bertambah, biayanya meningkat tajam
- Setiap objek memiliki header objek untuk tipe, status sinkronisasi, dan sebagainya
- Objek dialokasikan di heap dan kemudian menjadi target GC
- Array berisi satu juta
Point pada kenyataannya terdiri dari satu juta pointer dan satu juta objek yang tersebar di seluruh heap
- “State of Valhalla” dari Brian Goetz menyebut tata letak memori seperti ini sebagai fluffy
- Yang diinginkan Valhalla adalah tata letak dense di mana data tersusun berdampingan
Kesenjangan perangkat keras dan batas escape analysis
- Alasan tata letak memori yang padat penting adalah kesenjangan kecepatan antara CPU dan memori
- Pada 1995, biaya akses memori mirip dengan operasi CPU
- Kini CPU puluhan kali lebih cepat daripada memori utama, dan cache menutup kesenjangan ini
- CPU biasanya membaca memori dalam unit cache line 64-byte
- Jika data padat dan tersusun berurutan, banyak nilai berguna bisa diambil sekaligus
- Jika harus mengikuti pointer ke objek yang tersebar, cache miss dapat terjadi dan bisa jauh lebih lambat daripada hit
- Escape analysis di JVM dapat menghilangkan sebagian alokasi objek
- Jika objek dinilai tidak “escape” ke luar bagian kode lokal, objek tidak dialokasikan di heap dan field-nya bisa diurai menjadi variabel atau register
- Namun escape analysis kurang dapat diprediksi dan rapuh
- Jika objek masuk ke field class lain, disimpan dalam array, diteruskan ke method yang kompleks, atau melintasi batas yang tak bisa dianalisis JIT, optimisasi bisa berhenti
- Refactoring kecil, pembaruan JDK, atau perubahan struktur kode saja dapat membuat objek kembali dialokasikan ke heap
- Jika demi performa orang meninggalkan objek dan mengenkode langsung sebagai byte mentah seperti
r, g, b, kecepatan memang bisa didapat, tetapi keamanan, keterbacaan, validasi, dan method akan hilang
Awal pada 2014 dan peralihan dari Q World ke L World
- Project Valhalla secara resmi dimulai pada 2014
- James Gosling saat itu menggambarkannya sebagai “six PhDs tied into a single knot”
- Para pencipta Java sudah menginginkan value type sejak era Java 1.0, tetapi pada 1995 masalahnya terlalu sulit sehingga ditinggalkan
- Tujuan awalnya adalah memulihkan keselarasan antara model pemrograman dan karakteristik performa perangkat keras modern
- Arah yang dituju adalah memungkinkan pengguna mendeklarasikan tipe yang flat dan dense seperti primitive, tetapi tetap terlihat dan berperilaku seperti class biasa
- Prototype awal mengarah ke Q World
- Value type baru dipandang sebagai entitas yang secara fundamental berbeda dari objek, dengan type descriptor, bytecode, dan top type tersendiri
- Seluruh sistem tipe JVM jadi harus memiliki dua variasi, sehingga kompleksitas meningkat
- L World yang muncul sekitar 2019 menjadi titik balik
- Value type berbagi “L carrier” yang sama dengan referensi biasa
- Tim memperkirakan integrasi ini akan sulit, tetapi ternyata berjalan tanpa kompromi besar dan menyelesaikan berbagai masalah dari prototype sebelumnya
- Di L World, muncul pemisahan penting
- Model JVM dan model bahasa tidak harus tumpang tindih 100%
- JVM dapat memakai model L World, sementara programmer diberi model bahasa yang lebih nyaman
- Setelah itu, pekerjaan dibagi menjadi dua tahap: value class dan generic terspesialisasi
Perubahan nama dan model
- Istilah Valhalla berubah beberapa kali, dan itu bukan sekadar pergantian nama, melainkan mencerminkan perubahan model
- Istilah awalnya adalah value types
- Saat itu, belum sepenuhnya jelas tipe ini sebenarnya seperti apa
- Sekitar 2019~2020, model inline classes mulai terbentuk
- Kelas yang sudah ada diperlakukan sebagai identity classes, sedangkan kelas baru dibedakan sebagai inline classes tanpa identity
- inline class pada dasarnya final, field-nya final, dan ada batasan bahwa ia tidak bisa disinkronkan
- “State of Valhalla” tahun 2021 membahas primitive classes dan model dua projection
- Gagasannya adalah satu tipe memiliki value variant yang flat dan tidak bisa null, serta reference variant yang mengizinkan null
- Sintaks seperti
Point.val / Point.ref, lalu Point! / Point?, juga pernah diuji
- Model ini kuat, tetapi memiliki beban kognitif yang besar
- Programmer harus memahami dua bentuk dari tipe yang sama dan kapan konversi terjadi dalam penggunaan sehari-hari
- Pada akhirnya, dualisme itu diperkecil untuk menyederhanakan model bagi pengguna
- Saat ini JEP 401 menggunakan value class dan value object
- value class dideklarasikan dengan modifier
value
- Instance-nya adalah value object tanpa identity
- value class tetap merupakan reference type
- Non-nullability dipisahkan ke JEP opsional tersendiri, Null-Restricted Value Class Types
- Ini tidak termasuk dalam JDK 28
- Artikel lama yang menjelaskan model “primitive classes” sebelumnya bisa jadi berbeda dari standar OpenJDK saat ini
- JEP 401 juga hadir bersama preview JEP 402: Enhanced Primitive Boxing
- Arahannya adalah membuat konversi antara primitive dan wrapper lebih mulus
- Jangan berasumsi semuanya akan masuk bersama JEP 401 dalam bentuk yang sudah final
Model value class di JDK 28
- value class dideklarasikan dengan modifier
value
value class USDCurrency implements Comparable<USDCurrency> {
private int cents; // implicitly final
public USDCurrency(int dollars, int cents) {
this.cents = dollars * 100 + cents;
}
public USDCurrency plus(USDCurrency that) {
return new USDCurrency(0, this.cents + that.cents);
}
// dollars(), cents(), compareTo(), toString()...
}
- value record juga dimungkinkan
- Aturan utamanya sebagai berikut
- Semua instance field bersifat implicitly final
- method tidak boleh
synchronized
- kelas secara default bersifat final
- hierarki yang terdiri dari value class dan abstract value class dimungkinkan
- tidak bisa mewarisi kelas yang memiliki identity
- implementasi interface diperbolehkan
- Sifat intinya adalah tidak memiliki identity
- Objek biasa, meskipun isinya sama, jika dibuat dua kali dengan
new Point(1, 2) tetap merupakan dua objek berbeda
- value object tidak memiliki identity, sama seperti pada nilai
int 4 tidak ada “dua angka 4 yang berbeda”
Perubahan pada ==, synchronized, dan null
- Pada value object,
== bukan perbandingan identity, melainkan pemeriksaan substitutability
- Ia membandingkan secara rekursif apakah kelasnya sama dan nilai field-nya sama
- field primitive dibandingkan per bit, dan field object dibandingkan lagi dengan
==
new USDCurrency(3,95) == new USDCurrency(3,95) akan bernilai true
- Namun karena
== melihat state internal, untuk pertanyaan “apakah merepresentasikan data yang sama”, equals biasanya lebih tepat
- value object tidak memiliki identity yang bisa dipakai untuk sinkronisasi
- Jika sinkronisasi dicoba, akan muncul IdentityException
- Jika perlu memastikan identity secara eksplisit, bisa menggunakan
Objects.requireIdentity dan Objects.hasIdentity
- value class di JDK 28 tetap bisa bernilai null
USDCurrency d = null; adalah sah
- Tipe yang melarang null akan hadir lewat JEP terpisah di masa depan, dan belum ada di JDK 28
- Non-nullability bukan sekadar soal sintaks, tetapi juga menjadi tuas performa yang membuka perataan value class yang lebih besar
Skalarisasi dan perataan heap
- JEP 401 memberi JVM kebebasan untuk mengoptimalkan value object
- Skalarisasi (scalarization) adalah teknik JIT yang memecah reference value object menjadi sekumpulan field
- Alih-alih mengoper pointer
Color, JVM bisa mengoper byte r, g, b dan flag apakah null
- Biaya alokasi dan GC bisa hilang
- Ini mirip escape analysis, tetapi lebih dapat diprediksi, dan bisa diterapkan melewati batas pemanggilan method yang tidak di-inline
- Skalarisasi memiliki keterbatasan
- Jika tipe variabel adalah supertype value class seperti
Object atau parameter generic yang sudah di-erasure, biasanya ini tidak bekerja
- Dalam kasus seperti itu, objek harus dimaterialisasi di heap
- Perataan heap (heap flattening) adalah cara menulis nilai field dari value object langsung ke field atau sel array dengan mengenkodenya sebagai bit vector yang ringkas
- Tidak perlu pointer yang menunjuk ke lokasi heap lain
- Ini menghasilkan kepadatan data dan locality
- Data yang sudah diratakan harus bisa dibaca dan ditulis secara atomic untuk menghindari tearing saat akses konkuren
- Pada platform umum, ukuran yang “cukup kecil” bisa berada di kisaran 64-bit termasuk flag null
- value class kecil mungkin bisa diratakan dengan baik, tetapi bahkan dua field
int atau satu double saja bisa tidak cocok dengan ukuran atomic write sehingga menjadi objek heap biasa
- Ke depan, encoding 128-bit dan null-restricted type dapat memungkinkan perataan value class yang lebih besar
Dampak pada boxing, wrapper, dan array
- Jika preview diaktifkan, primitive wrapper class seperti
Integer, Long, dan Double sendiri akan menjadi value class
- Karena box kehilangan identity, JVM dapat melakukan skalarisasi dan perataan
Integer[] akan bergerak mendekati efisiensi int[], dan overhead boxing akan berkurang besar
- JEP 402: Enhanced Primitive Boxing memperluas konversi antara primitive dan box
- Ini membuka jalan menuju ekspresi seperti
List<int>, tetapi masih merupakan pekerjaan terpisah yang sedang dimatangkan
- Efeknya paling jelas terlihat pada array
Color[] pada model lama bisa menjadi sejuta pointer dan sejuta objek yang tersebar di heap
- value class
Color[] bisa menjadi contiguous block yang langsung menyimpan nilai warna secara berurutan
- CPU dapat membaca banyak nilai secara berurutan per cache line
Perbedaan sebelum dan sesudah lewat contoh Point[]
- Contoh class biasa sebelum Valhalla adalah sebagai berikut
final class Point {
final int x;
final int y;
Point(int x, int y) { this.x = x; this.y = y; }
}
Point[] points = new Point[1_000_000];
- Array ini menampung satu juta pointer
- Setiap pointer menunjuk ke objek
Point terpisah di suatu lokasi di heap
- Setiap objek memiliki header objek selain dua
int
- Saat diiterasi, pointer harus dibaca, lalu lompat ke alamat tersebut, kemudian membaca field-nya
- Setelah Valhalla, contoh value class menjadi seperti berikut
value class Point {
final int x;
final int y;
Point(int x, int y) { this.x = x; this.y = y; }
}
Point[] points = new Point[1_000_000];
- Perbedaan pada kode hanya satu kata, yaitu
value, tetapi tata letak memorinya berubah
- JVM dapat menyimpan nilai setiap point secara rapat langsung di dalam array
- Tidak ada header maupun pointer untuk setiap elemen
- Berdasarkan dua
int x, y, data dapat disusun berurutan sebagai 8 byte ditambah kemungkinan null flag
- Maintainability juga tetap terjaga
Point tetap merupakan class yang memiliki nama, konstruktor, validasi, dan method
- Anda bisa menghindari pendekatan memecahnya menjadi
int[] xs, int[] ys lalu mencocokkan indeksnya
Mengapa specialized generics masih tersisa
- Java generics diimplementasikan dengan type erasure
List<String> dan List<Integer> adalah List yang sama saat runtime
- type parameter
T di-erasure menjadi Object
- Erasure adalah pilihan yang disengaja agar generics bisa diperkenalkan tanpa merusak codebase Java yang sudah ada
- Bahkan jika class non-generic diubah menjadi generic, source file dan compiled class yang lama tetap tidak rusak
- Valhalla dan erasure bertabrakan dari sisi performa
- Jika value object dimasukkan ke
List<Point>, T akan di-erasure menjadi Object, sehingga objek itu harus dimaterialisasi di heap
- Keuntungan flattening yang didapat dari
Point[] bisa hilang di ArrayList<Point>
- Rencana pemulihannya terdiri dari dua tahap
- Universal Generics: pada level bahasa, type variable akan bisa menangani value type juga
- Tetap masih memakai erasure
- Karena field
T secara default dimulai dari null, bisa muncul compiler warning “null pollution”
- Jika warning itu diselesaikan, API akan menjadi lebih dekat ke kondisi specialization-ready
- Specialized Generics: pada level JVM, akan dibuat layout class yang terspesialisasi untuk tiap concrete type argument
- Dalam istilah proyek, species dan type restriction berkaitan dengan tahap ini
- Baru pada tahap inilah
ArrayList<Point> bisa benar-benar memakai memori flat
- JDK 28 belum memiliki full specialized generics
- Koleksi, stream, dan API yang menjadi flat serta bebas alokasi di atas value type masih merupakan pekerjaan untuk rilis mendatang
Yang ada dan yang tidak ada di JDK 28
- Yang masuk ke JDK 28 adalah sebagai berikut
- deklarasi
value class dan value record
- migrasi ke value class untuk sebagian value-based class yang sudah ada di JDK, termasuk class seperti primitive wrapper
- skalarisasi dan flattening untuk class yang memenuhi syarat
- boxing yang lebih murah
- Yang belum ada di JDK 28 adalah sebagai berikut
- null-restricted types
- full specialized generics
- encoding 128-bit
- JEP 402 yang benar-benar matang
- Karena ini adalah preview feature, syntax dan perilakunya bisa berubah di setiap rilis sesuai feedback
- JDK 28 bukan LTS
- LTS berikutnya kemungkinan besar adalah JDK 29 pada September 2027
- Banyak perusahaan mungkin akan bertemu Valhalla yang sudah stabil di LTS, tetapi preview JDK 28 memulai feedback loop dari kode nyata
Perubahan yang akan terjadi pada ekosistem dan kode
- Di ranah Java performa tinggi, Valhalla menjadi jalur untuk menangani data padat tanpa mengorbankan abstraction
- Ini mencakup area seperti pemrosesan data, komputasi vektor, ML, pengembangan game, keuangan, dan codec
- Framework dan library dapat mulai melakukan migrasi value-based class
- Kode yang bergantung pada identity bisa mengalami perbedaan perilaku
== pada value object tidak lagi berarti perbandingan alamat, melainkan perbandingan substitutability
synchronized pada value object akan berujung pada IdentityException
- Walaupun
Integer menjadi value class, pada kebanyakan kasus binary tetap akan terus terhubung
- Compilation error baru muncul jika mencoba melakukan sinkronisasi pada tipe seperti ini
== yang bergantung pada identity Integer atau synchronized(someInteger) bisa terdampak
- Build early-access tersedia di jdk.java.net/valhalla
Ringkasan pertanyaan yang sering muncul
- value class berbeda dari record
record adalah pilihan bahwa content dinyatakan sebagai component
value adalah pilihan untuk melepaskan identity
- Kombinasi class biasa, record, value class, dan value record semuanya dimungkinkan
- value object bisa dibandingkan dengan
==
- Maknanya bukan perbandingan alamat, melainkan substitutability
- Untuk kesetaraan data yang direpresentasikan, biasanya
equals lebih tepat
- value class di JDK 28 masih bisa bernilai null
- non-nullable type adalah JEP masa depan
- Ini juga penting untuk flattening pada value class yang lebih besar
ArrayList<Point> flat yang cepat masih belum ada
- Karena type erasure, objek di dalam generic collection harus dimaterialisasi di heap
- Di JDK 28, contoh utama flattening yang bekerja langsung adalah field dari value type dan array seperti
Point[]
- escape analysis tidak bisa menggantikan semuanya
- Jika objek keluar ke field, array, atau melewati batas analisis, optimisasi bisa gagal
- Skalarisasi value object lebih dapat diprediksi dan bisa melampaui batas method call lebih jauh
- Valhalla secara keseluruhan akan berkembang lintas beberapa rilis
- JDK 28 adalah preview pertama untuk value class
- specialized generics, null-restricted types, dan encoding 128-bit adalah pekerjaan yang tersebar ke rilis-rilis mendatang
2 komentar
Virtual thread yang dirilis setelah waktu yang lama melalui Project Loom itu praktis dan menyelesaikan banyak hal di level runtime JVM, jadi beban yang perlu dipikirkan developer relatif lebih sedikit.
Semoga Project Valhalla juga saat rilis final nanti terasa mendekati “makan siang gratis” seperti itu.
Komentar Hacker News
Katanya perbedaan memori itu hal yang mendasar, tapi saya jadi ragu apakah tulisan ini benar-benar direview dengan baik
Bukankah barusan dijelaskan bahwa objek dengan representasi lebih dari 64 bit tidak bisa di-flatten di heap? Contoh
Pointpunya dua bilangan bulat 32 bit plus flag null, jadi minimal 65 bitMelihat ungkapan seperti “mungkin ada flag null” dan kalimat-kalimat penegasan pendek setelahnya, rasanya seperti AI sedang membuat kalimat penekanan lalu malah keluar jalur, dan blok
"[IMAGE: the same Point[] array in two variants..."di tengah itu juga disayangkanTidak masalah memakai AI untuk membantu menulis, tapi kalau tidak memasukkan suara sendiri, tidak ada alasan untuk membacanya
https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing#...
Tapi setelah beberapa paragraf, jadi jelas bahwa ini tulisan yang melewati LLM atau dibuat dengan cara yang lebih buruk lagi
Baik blog teknis atau apa pun, tolong jangan biarkan AI yang menulis menggantikan manusia. Tidak ada yang ingin membaca tulisan seperti itu
Hari ini saya jadi tahu bahwa Rust punya
NonZeroU64, dan bila digabungkan denganOptional, kita bisa mendapatkan perilaku yang dibutuhkan dengan hanya 64 bit per entrihttps://doc.rust-lang.org/std/num/type.NonZeroU64.html
Seperti yang juga jelas di JEP, ini hanyalah hasil pertama dari fitur yang sangat besar, dan seperti fitur-fitur Java belakangan ini, pengirimannya dilakukan sedikit demi sedikit
Tentu saja tujuannya adalah mem-flatten nilai yang lebih besar juga, dan mekanismenya sudah ada di dalam JVM. Yang tersisa hanyalah mengekspresikan di level bahasa bahwa “tearing diperbolehkan”
Saya mengakui besarnya upaya yang benar-benar masuk ke Valhalla, tapi saya sulit setuju dengan tafsiran bahwa “modelnya kuat tetapi secara mental terasa berat”
Mengatakan bahwa sebuah variabel tidak bisa bernilai null bukanlah pembedaan yang memberatkan secara mental, apalagi jika semuanya ditandai dengan cukup jelas
Sikap “menyederhanakan model pengguna meski harus mengorbankan batas atas performa” justru bisa jadi memang memberikan penyederhanaan bagi pengguna
Sistem tipe bahasa pemrograman ada untuk memberi jaminan yang nyaman bagi pengembang di atas CPU yang pada dasarnya hanya bisa memproses angka. Tidak perlu mengurangi jaminan keamanan opsional hanya karena dianggap “terlalu rumit”
Bahkan setelah sampai pada pemahaman bahwa “model bahasa dan model JVM tidak harus 100% tumpang tindih” pun tetap begitu
Tata kelola Java terlihat kurang memadai, dan ini sangat kontras terutama dengan .NET yang sejak awal umumnya mengambil keputusan yang benar
Belakangan saya juga bertanya-tanya apakah Java masih punya nilai atau perhatian di dalam Oracle. Sekarang perusahaan itu terlihat seperti bisnis data center/komputasi dengan aktivitas warisan dan utang besar yang menempel
Kadang saya merasa satu-satunya bagian Oracle yang masih benar-benar menghasilkan uang hanyalah tim legal dan divisi pemotong rumput
Dan penanda null juga akan datang: https://openjdk.org/jeps/8303099
Hanya saja memang harus dirilis bertahap, dan PR untuk memperkenalkan value class/object ini saja sudah berukuran 200 ribu baris
Sepertinya bukan berarti itu mustahil, hanya saja Anda tidak bisa memakan seekor gajah dalam sekali suap
Meski begitu, satu kaki ini memang sudah dikunyah cukup lama
Jika ini konsep yang sudah terselesaikan sejak 2012, tidak ada alasan untuk memasukkan berbagai rasa state langsung ke dalam bahasa. Rel hanya menuju A atau B, dan yang menentukan jalurnya adalah keadaan muatan keretanya
Kalau suatu konsep terus muncul lalu menghilang hingga memicu perang bahasa, itu tanda bahwa ada kebutuhan yang tidak ditangani dengan baik oleh bahasa tersebut, atau ditangani dengan cara yang menciptakan beban mental
Hal-hal seperti
Value,Errorstates,Null,IoExceptions,WeirdOsStatesNeededToHandleUpstairshttps://fsharpforfunandprofit.com/rop/
Meminjam gaya Monty Python, sekarang mari kita lanjut saja
Integer/intTim Valhalla, alih-alih memberi setiap tipe proyeksi yang punya identitas dan yang tidak, membuat value type sama sekali tidak memiliki identitas, sehingga
Integerdanintmenjadi sinonimTata letak memori lalu ditentukan otomatis berdasarkan konteks dan keputusan optimisasi. Karena itu makna
==untuk wrapper primitif sepertiIntegerjuga berubah, dan sekarang tidak lagi bergantung pada apakah kita memakai “proyeksi referensi” atau “proyeksi nilai”Tidak ada pengurangan jaminan keamanan opsional dengan alasan “memberatkan secara mental” yang terjadi di sini
Dalam komentar HN terkait Java/JVM, hal yang berulang terlihat adalah betapa mengejutkannya banyak orang masih punya citra lama tentang JVM atau Java, tetapi hampir tidak tahu wujudnya saat ini
JVM tahun 2026 adalah predator yang sangat sehat. Apakah ada kekurangannya? Tentu saja, tetapi fondasinya luar biasa bagus
Di pekerjaan saya memakai Java 26 terbaru dan fitur pratinjau, terutama
StructuredConcurrency, dan itu luar biasa. Bahkan dari sudut pandang seseorang yang di perusahaan-perusahaan sebelumnya memakai Haskell dan Python, saya sama sekali tidak menyesalSecara pribadi saya tahu fitur-fitur baru yang keluar dalam beberapa tahun terakhir, tetapi di pekerjaan nyata Java secara harfiah masih terjebak di masa lalu
Banyak komentar di sini agak tidak adil dibanding pekerjaan hebat yang sedang berlangsung sekarang dan JEP yang akan datang yang bahkan lebih keren
Kalau Java diibaratkan anak, beberapa tahun pertamanya dibesarkan oleh orang tua penuh kasih (Sun), lalu setelah itu dilempar ke garasi bersama anak-anak lain dan ditelantarkan oleh wali yang jahat (Oracle)
Karena ditelantarkan dan tidak dicintai sampai JDK 8, pada dasarnya Java selama ini sedang mengejar ketertinggalan
Pernyataan seperti “baru sekarang ada struct atau value type” memang benar, tetapi itu karena pertumbuhannya terhambat oleh proses korporat yang besar, birokratis, dan bermusuhan. Sekarang Java sudah bebas dan dicintai melalui keluarga OpenJDK
Ke depan kita akan terus menikmati kegembiraan tulis sekali, distribusikan ke mana saja
Lebih tepatnya, ia dibesarkan oleh orang tua penuh kasih, lalu karena masalah keuangan dititipkan ke keluarga asuh dan di sanalah ia ditelantarkan
Setelah itu ia diadopsi oleh orang tua baru yang penuh kasih, yaitu Oracle, dan Java pun berkembang menjadi orang dewasa yang sehat dan stabil
Oracle juga yang menjadikan OpenJDK implementasi referensi dan menyelesaikan open-source platform tersebut, serta meng-open-source alat yang sebelumnya tertutup seperti JFR dan Mission Control
Mereka juga mempertahankan banyak anggota asli tim bahasa, sesuatu yang cukup jarang dalam akuisisi seperti ini, dan Java meningkat besar baik di sisi bahasa maupun runtime
Oracle mendorong Java maju dengan kecepatan yang belum pernah ada sebelumnya sambil tetap mempertahankan sebagian besar kompatibilitas ke belakang
.NET disebut “melakukannya dengan benar dari awal”, tetapi kalau yang dimaksud adalah pemisahan dan penulisan ulang .NET Framework/.NET Core/.NET, itu pun tidak masuk akal bahkan dalam diskusi ini. .NET bisa belajar dari Java, tetapi tetap ada bagian yang mereka kacaukan
Hal yang sama berlaku untuk MySQL. Di situs ini orang bilang “sudah mati”, tetapi bagi orang yang benar-benar paham, ia justru hidup kembali di bawah Oracle
Versi Java terakhir di bawah Sun keluar pada 2006, Oracle membeli Sun pada 2010, JDK 7 keluar pada 2011, dan JDK 8 pada 2014
Timnya pada umumnya tetap sama, dan perbedaan terbesarnya adalah Oracle mengakhiri penelantaran itu dan menaruh lebih banyak dana. Karena itulah laju Java meningkat setelah akuisisi
Disebut “mengejar ketertinggalan”, tetapi juga tidak jelas sebenarnya mengejar siapa. Bahasa yang sama atau lebih populer dari Java hanya JS/TS dan Python
Orang yang bilang Java tertinggal biasanya membandingkannya dengan bahasa yang performanya jauh lebih buruk daripada Java. Orang yang menyukai fitur tertentu sering luput melihat bahwa bahasa yang memiliki fitur itu tetap lesu bukan karena tidak punya fitur tersebut, melainkan justru meskipun punya fitur itu
Para manajer suka rilis yang cepat, sedangkan kepemimpinan teknis, bahkan sejak era Sun, justru bersikeras bahwa semuanya harus dilakukan dengan hati-hati, pelan, dan benar
Saya paham suasana yang merasa Java tidak sepopuler tahun 2003, tetapi masa itu adalah periode yang sangat terpadu secara luar biasa bukan hanya untuk Java melainkan untuk seluruh ekosistem perangkat lunak, dan sebelum maupun sesudahnya tidak pernah seterpadu itu
Sekarang teknologi yang benar-benar tulis sekali, distribusikan ke mana saja adalah WebAssembly. JVM sudah pernah mendapat gilirannya, dan kalah
Meski begitu, saya tetap tidak akan menyebut Java sampai “terhambat pertumbuhannya”. Ia membuat pilihan, sebagian masuk akal dan sebagian tidak, dan pilihan seperti itu sangat sulit diperbaiki di kemudian hari
Lihat saja C++; menurut saya kompatibilitas-sebagian dengan C adalah albatros sepanjang 150 kaki yang mustahil diperbaiki, dan banyak versi setelah C++11 adalah upaya membuat albatros itu sedikit lebih bisa ditanggung
Di JVM, memperlakukan semua value class sebagai satu L-type tunggal seperti tipe primitif menurut saya adalah solusi yang cukup rapi untuk masalah yang sulit
Pada akhirnya semua ini berakar pada keputusan Java 2 untuk mengimplementasikan generics dengan type erasure demi kompatibilitas ke belakang, dan C3 melihat hasilnya lalu menolak menempuh jalan itu
Hanya dari evolusi value type di Java saja rasanya bisa ditulis satu novel thriller teknologi
Saya membaca mailing list dan menonton semua video terkait, dan proses menyatukan desainnya menjadi sesuatu yang selalu terasa khas Java benar-benar mengesankan
Pada saat yang sama, pembahasannya juga menggali jauh lebih rinci apa arti value type dan optimisasi apa yang bisa dilakukan, serta di bagian mana
valuePada value class,
==pada dasarnya jadi bekerja sepertimemcmp()Ini agak disayangkan, karena merusak enkapsulasi dan mengungkap detail implementasi
Kode klien bisa bercabang tergantung bagaimana suatu nilai direpresentasikan secara internal. Dalam beberapa hal ini bahkan lebih buruk daripada perbandingan identitas, karena perbandingan identitas setidaknya tidak mengekspos keadaan internal
Ini bukan melakukan OOP klasik dengan cara baru, melainkan bahasa yang lahir dari ideologi OOP melangkah lebih jauh ke dunia pasca-OOP
Saya rasa pihak Java pasti sudah cukup memikirkan hal-hal seperti mengecualikan padding dari perbandingan atau memaksa byte padding menjadi 0
Ini juga harus berlaku untuk string. String jelas akan tetap dialokasikan di heap, dan melakukan
memcmppada pointer di dalam “struct” baru berarti tepatnya melakukan perbandingan identitasJava memisahkan pemeriksaan identitas objek dan pemeriksaan kesetaraan.
==pada dasarnya melihat apakah dua pointer sama, sedangkan kesetaraan adalah konsep subjektif yang berbasis antarmuka sepertiequals/hashCodeJadi
new Integer(1000) == new Integer(1000)dulufalsetetapi sekarang menjaditrue, dannew Integer(1000).equals(new Integer(1000))adalahtrue, sementaranew Integer(10) == new Long(10)dulufalsetetapi sekarang menjadi galat kompilasiDi Java lama, integer di bawah nilai tertentu sering diganti dengan tipe yang dinormalkan, dan seingat saya angkanya sekitar 128. Karena itu ada perbedaan antara 10 dan 1000
Sekarang tampaknya perbandingan di atas secara implisit melakukan unboxing. Fakta bahwa perbandingan
Integer/Longdulufalsedan sekarang menjadi galat kompilasi jelas menunjukkan bahwa unboxing ikut terlibatMungkin dengan variabel Anda masih bisa mendapatkan perilaku lama
Bagaimanapun, jika value class kehilangan identitas, maka
==berubah dari kesetaraan pointer menjadi kesetaraan bit-level. Saya harap berbagai kasus pinggiran seperti ini diselesaikan, tetapi secara teknis ini memang perubahan yang merusakSaya paham tujuan value class, tetapi implementasinya cacat
Kode berikut akan mencetak apa?
Point a = new Point(10, 10); Point b = a; a.x = 100; System.out.println(b.x);Sampai sekarang jawabannya jelas, tetapi jika value class ditambahkan, jawabannya bergantung pada apakah
Pointadalah value class atau reference class. Karena itu desain ini merusak keterbacaanIni adalah pelanggaran terhadap prinsip keseragaman. Dalam The Psychology of Computer Programming karya Weinberg, keseragaman dijelaskan sebagai prinsip psikologis bahwa pengguna mengharapkan hal-hal yang tampak mirip akan bekerja dengan cara yang mirip, dan hal-hal yang tampak berbeda akan bekerja berbeda
Jika bahasa pemrograman mengizinkan dua konstruksi yang di titik penggunaan tampak hampir sama memiliki perilaku semantik yang berbeda, beban kognitif pembaca meningkat. Untuk mengetahui apakah assignment, kesetaraan, identitas, dan mutasi bekerja seperti objek referensi biasa atau seperti nilai, pembaca harus memeriksa deklarasi tipe atau bergantung pada alat
Ini bisa diperbaiki jika kata kunci
valuediwajibkan bukan hanya saat deklarasi tetapi juga saat penggunaan. Misalnya ditulis sepertivalue Point a = new Point(10, 10);https://openjdk.org/jeps/401
finalTentu saja, hanya dari empat baris itu tidak ada cara untuk tahu hal seperti itu akan terjadi, tetapi masalah ini sebenarnya juga sudah ada sekarang. Hal yang sama akan terjadi jika
Pointadalah recorda.x = 100;tidak akan valid. Tipe record bersifat immutableJadi situasi yang dikhawatirkan seharusnya tidak mungkin terjadi
Jika ditulis seperti
value Point a = new Point(10, 10); value Point b copy= a; a.x uniq= 100; System.out.println(b.x);, akan jauh lebih jelas bahwa terjadi kloning/penyalinan dan bahwa perubahan field tidak memengaruhi field objek lainSaya tahu di dunia Java mengakui keberadaan .NET itu seperti kurang sopan, tetapi saya penasaran bagaimana ini berbeda dari struct .NET
Jika melihat sekilas value type, spesialisasi generik, dan boxing, tampaknya mereka membuat pilihan yang sama
Jika C# pada sudut pandang level rendah sebagian besar menyalin C, pihak Java mendekatinya dari level tinggi dan menganalisis secara rinci batasan mana yang memberi keuntungan apa
Di bahasa lain, pembagian struct/class bersifat dikotomis, tetapi Java memungkinkan kontrol yang lebih rinci dengan mencerminkan makna domain dasarnya
Dan pada struct khususnya, ternyata ada berbagai senjata makan tuan terutama dalam konteks paralel
Secara pribadi saya melihat struct di C/C# bisa diubah dan diteruskan lewat penyalinan, sedangkan value class tidak bisa diubah dan diteruskan sebagai nilai
Saya rasa alokasi stack tidak bisa dilakukan di Java
Dikotomi palsu seperti “struct C# punya identitas dan mutabilitas sehingga semantik penyalinan saat assignment atau passing harus didefinisikan secara tepat, dan karena itu memberi model yang lebih berat bagi programmer serta lebih sedikit kebebasan bagi runtime” tidak terlalu cocok dengan apa yang sedang dijelaskan
Referensi kelas Java mungkin tidak punya identitas dalam arti semantik Java, tetapi dalam arti struktur memori unik pada alamat tertentu tentu saja tetap punya identitas. Ini nyaris sekadar bermain kata pada terminologi Java
Catatan kaki 6 tentang “apa bedanya dengan
structdi C#” tidak akuratMelihat artikel itu dipenuhi gambar buatan AI, saya jadi bertanya-tanya apakah tulisan itu, atau setidaknya proses risetnya, juga penuh halusinasi
Tulisannya agak samar dan dramatis, tetapi syukurlah dokumen aslinya cukup mudah dibaca
Halaman tingkat atas: https://openjdk.org/projects/jdk/28/spec/
Status JEP: https://bugs.openjdk.org/secure/Dashboard.jspa?selectPageId=...
Akan bagus kalau ada yang melacak perkembangan terkait di C#, Swift, Java, dan Rust. Menurut saya, semuanya telah berlomba untuk mengejar perangkat keras dan saling memengaruhi
Secara pribadi, saya khawatir perubahan-perubahan ini akan berdampak pada berbagi memori FFI