Belum lama ini,
JavaScript memiliki tipe data
BigInt primitif baru untuk bekerja dengan angka presisi acak. Informasi minimum yang diperlukan telah
diberitahukan /
diterjemahkan tentang motivasi dan kasus penggunaan. Dan saya ingin memberi sedikit lebih banyak perhatian pada "penjelas" lokal yang berlebihan dalam casting tipe dan
TypeError yang tidak terduga. Akankah kita memarahi atau memahami dan memaafkan (lagi)?
Tersirat menjadi eksplisit?
Dalam bahasa di mana konversi tipe implisit telah lama digunakan, itu telah menjadi meme dari hampir semua konferensi dan hanya sedikit orang yang terkejut dengan kerumitan seperti:
1 + {};
Kami tiba-tiba mendapatkan TypeError, mencoba menambahkan dua ANGKA yang tampaknya:
1 + 1n;
Dan jika pengalaman sebelumnya tentang hal-hal tersirat tidak mengarah pada gangguan dalam belajar bahasa, maka ada kesempatan kedua untuk memecah dan membuang buku teks ECMA dan pergi ke beberapa Jawa.
Selanjutnya, bahasa ini terus “troll” pengembang js:
1n + '1';
Oh ya, jangan lupa tentang operator
+ unary:
+1n;
Singkatnya, kita tidak dapat mencampur
BigInt dan
Number dalam operasi. Akibatnya, tidak disarankan untuk menggunakan "bilangan bulat besar" jika 2 ^ 53-1 (
MAX_SAFE_INTEGER ) cukup untuk tujuan kita.
Keputusan kunci
Ya, ini adalah keputusan utama dari inovasi ini. Jika Anda lupa bahwa ini adalah JavaScript, maka semuanya sangat logis: konversi implisit ini berkontribusi pada hilangnya informasi.
Ketika kami menambahkan dua nilai dari tipe numerik yang berbeda (bilangan bulat besar dan angka floating-point), nilai matematika dari hasilnya mungkin di luar kisaran nilai yang mungkin. Misalnya, nilai ekspresi
(2n ** 53n + 1n) + 0,5 tidak dapat secara akurat diwakili oleh salah satu dari jenis ini. Ini bukan lagi bilangan bulat, melainkan bilangan real, tetapi akurasinya tidak lagi dijamin oleh
format float64 :
2n ** 53n + 1n;
Dalam sebagian besar bahasa dinamis, di mana jenis bilangan bulat dan float diwakili, yang pertama ditulis sebagai
1 , dan yang terakhir ditulis sebagai
1.0 . Jadi, selama operasi aritmatika dengan adanya pemisah desimal dalam operan, kita dapat menyimpulkan bahwa akurasi float dalam perhitungan dapat diterima. Tetapi JavaScript bukan salah satunya, dan
1 adalah pelampung! Dan ini berarti komputasi
2n ** 53n + 1 akan
menghasilkan float 2 ^ 53. Yang, pada gilirannya, merusak fungsi utama
BigInt :
2 ** 53 === 2 ** 53 + 1;
Yah, tidak ada alasan untuk membicarakan implementasi
"menara numerik" juga, karena Anda tidak akan berhasil mengambil nomor yang ada sebagai tipe data numerik umum (untuk alasan yang sama).
Dan untuk menghindari masalah ini, para pemain implisit antara
Number dan
BigInt dalam operasi dilarang. Akibatnya, "bilangan bulat besar" tidak dapat dengan aman dilemparkan ke fungsi JavaScript atau API Web apa pun, di mana angka yang biasa diharapkan:
Math.max(1n, 10n);
Anda harus secara eksplisit memilih salah satu dari dua jenis dengan menggunakan
Number () atau
BigInt () .
Selain itu, untuk operasi dengan tipe campuran, ada
penjelasan tentang implementasi yang kompleks atau kehilangan kinerja, yang cukup umum untuk inovasi bahasa kompromi.
Tentu saja, ini berlaku untuk konversi numerik implisit dengan primitif lainnya:
1 + true;
Tetapi rangkaian berikut (sudah) akan berfungsi, karena hasil yang diharapkan adalah string:
1n + [0];
Pengecualian lain adalah dalam bentuk operator perbandingan (seperti
< ,
> dan
== ) antara
Number dan
BigInt . Juga tidak ada kehilangan keakuratan, karena hasilnya adalah Boolean.
Nah, jika Anda mengingat tipe data
Simbol baru sebelumnya, apakah TypeError tidak lagi tampak seperti penambahan yang radikal?
Symbol() + 1;
Dan ya, tapi tidak. Memang, secara konseptual simbol bukanlah angka sama sekali, tetapi keseluruhan - sangat banyak:
- Sangat tidak mungkin bahwa simbol akan jatuh ke dalam situasi seperti itu. Namun, ini sangat mencurigakan dan TypeError cukup sesuai di sini.
- Sangat mungkin dan biasa bahwa "keseluruhan besar" dalam operasi akan berubah menjadi salah satu operan ketika benar-benar tidak ada yang salah.
Operator unary
+ melempar pengecualian karena masalah kompatibilitas dengan
asm.js , di mana
Number diharapkan. Plus unary tidak dapat bekerja dengan
BigInt dengan cara yang sama seperti
Nomor , karena dalam kasus ini kode asm.js sebelumnya akan menjadi ambigu.
Tawaran alternatif
Meskipun relatif sederhana dan "bersih" dari implementasi
BigInt ,
Axel Rauschmeyer menekankan kurangnya inovasi. Yakni, satu-satunya kompatibilitas mundur sebagian dengan
Nomor yang ada dan yang berikutnya:
Gunakan Angka hingga int 53-bit. Gunakan Integer jika Anda membutuhkan lebih banyak bit
Sebagai alternatif, ia
mengusulkan yang berikut ini .
Biarkan
Number menjadi supertype untuk
Int dan
Double baru :
- typeof 123.0 === 'number' , dan Number.isDouble (123.0) === true
- typeof 123 === 'number' , dan Number.isInt (123) === true
Dengan fungsi baru untuk
konversi Number.asInt () dan
Number.asDouble () . Dan, tentu saja, dengan kelebihan operator dan gips yang diperlukan:
- Int × Double = Ganda (gips)
- Ganda × Int = Ganda (dengan gips)
- Ganda × Ganda = Ganda
- Int × Int = Int (semua operator kecuali divisi)
Menariknya, dalam versi yang disederhanakan, kalimat ini mengelola (pada awalnya) tanpa menambahkan tipe baru ke bahasa. Sebagai gantinya,
definisi The Number Type meluas: di samping semua kemungkinan angka presisi ganda 64-bit (IEEE 754-2008), angka sekarang termasuk semua bilangan bulat. Akibatnya, "angka yang tidak akurat"
123.0 dan "angka pastinya"
123 adalah angka yang terpisah dari tipe
Angka tunggal.
Itu terlihat sangat akrab dan masuk akal. Namun, ini merupakan peningkatan serius dari jumlah yang ada, yang lebih cenderung untuk “menghancurkan web” dan alat-alatnya:
- Ada perbedaan antara 1 dan 1.0 , yang sebelumnya tidak ada. Kode yang ada menggunakannya secara bergantian, yang setelah upgrade dapat menyebabkan kebingungan (tidak seperti bahasa di mana perbedaan ini ada pada awalnya).
- Ada efek ketika 1 === 1.0 (seharusnya merupakan peningkatan), dan pada saat yang sama, Number.isDouble (1)! == Number.isDouble (1.0) : sekali lagi, ini seperti itu.
- "Keunikan" kesetaraan 2 ^ 53 dan 2 ^ 53 + 1 menghilang, yang akan mematahkan kode yang bergantung padanya.
- Masalah kompatibilitas yang sama dengan asm.js dan banyak lagi.
Oleh karena itu, pada akhirnya, kami memiliki solusi kompromi dalam bentuk tipe data baru yang terpisah. Perlu ditekankan bahwa opsi lain juga dipertimbangkan dan
dibahas .
Ketika Anda duduk di dua kursi
Sebenarnya,
komentar komite dimulai dengan kata-kata:
Temukan keseimbangan antara menjaga intuisi pengguna dan menjaga presisi
Di satu sisi, saya akhirnya ingin menambahkan sesuatu yang "tepat" ke bahasa. Dan di sisi lain, untuk mempertahankan perilaku yang sudah akrab bagi banyak pengembang.
Hanya saja Anda tidak akan dapat menambahkan ini "tepat", karena Anda tidak dapat memecahkannya: matematika, ergonomi bahasa, asm.js,
kemungkinan perluasan lebih lanjut dari sistem jenis , produktivitas dan, pada akhirnya, web itu sendiri! Dan Anda tidak dapat memecahkan semuanya pada saat yang sama, yang mengarah ke hal yang sama.
Dan Anda tidak dapat menghentikan intuisi pengguna bahasa, yang tentu saja juga
diperdebatkan dengan panas . Benar, apakah berhasil?