Dari panduan bahasa Java 5 :
Ketika Anda melihat titik dua (:) membacanya sebagai "dalam".
Mengapa tidak menggunakan in
itu saja?
Ini telah menggangguku selama bertahun-tahun. Karena itu tidak konsisten dengan sisa bahasa. Misalnya, di Jawa ada implements
, extends
, super
untuk hubungan antara jenis bukan simbol seperti di C ++, Scala atau Ruby.
Di Jawa usus besar digunakan dalam 5 konteks . Tiga di antaranya merupakan warisan dari C. Dan dua lainnya disahkan oleh Joshua Bloch. Paling tidak, itulah yang dia katakan dalam pembicaraan "The closures controversy" . Ini muncul ketika ia mengkritik penggunaan tanda titik dua untuk pemetaan karena tidak konsisten dengan masing-masing semantik. Yang bagi saya tampaknya aneh karena itu adalah pola yang diharapkan untuk setiap penyalahgunaan. Suka list_name/category: elements
atau laberl/term: meaning
.
Saya sudah mengintai jcp dan jsr, tetapi tidak menemukan tanda-tanda mailing list. Tidak ada diskusi tentang masalah ini yang ditemukan oleh google. Hanya pemula yang bingung dengan arti titik dua di for
.
Argumen utama yang menentang in
sejauh ini:
- membutuhkan kata kunci baru; dan
- mempersulit lexing.
Mari kita lihat definisi tata bahasa yang relevan :
pernyataan : pernyataan 'untuk' '(' forControl ')' | ... ; forControl : enhancedForControl | forInit? ';' ekspresi? ';' untukMemutakhirkan? ; EnhancedForControl : variableModifier * type variableDeclaratorId ':' ekspresi ;
Ubah dari :
menjadi in
tidak membawa kompleksitas tambahan atau memerlukan kata kunci baru.
Jawaban:
Parser normal seperti yang diajarkan pada umumnya memiliki tahap lexer sebelum parser menyentuh input. Lexer (juga "pemindai" atau "tokenizer") memotong input menjadi token kecil yang dianotasi dengan suatu tipe. Ini memungkinkan parser utama untuk menggunakan token sebagai elemen terminal daripada harus memperlakukan setiap karakter sebagai terminal, yang mengarah pada peningkatan efisiensi yang nyata. Secara khusus, lexer juga dapat menghapus semua komentar dan ruang putih. Namun, fase tokenizer terpisah berarti bahwa kata kunci juga tidak dapat digunakan sebagai pengidentifikasi (kecuali bahasa tersebut mendukung stropping yang agak tidak disukai, atau mengawali semua pengidentifikasi dengan sigil seperti
$foo
).Mengapa? Mari kita asumsikan kita memiliki tokenizer sederhana yang memahami token berikut:
Tokenizer akan selalu cocok dengan token terpanjang, dan lebih suka kata kunci daripada pengidentifikasi. Jadi
interesting
akan digambarkan sebagaiIDENT:interesting
, tetapiin
akan digambarkan sebagaiIN
, tidak pernah samaIDENT:interesting
. Seperti cuplikan kodeakan diterjemahkan ke aliran token
Sejauh ini, itu berhasil. Tetapi variabel apa pun
in
akan lexed sebagai kata kunciIN
daripada variabel, yang akan memecahkan kode. Lexer tidak menyimpan status apa pun di antara token, dan tidak dapat mengetahui bahwain
biasanya merupakan variabel kecuali saat kita berada dalam for for loop. Juga, kode berikut ini harus legal:Yang pertama
in
akan menjadi pengidentifikasi, yang kedua akan menjadi kata kunci.Ada dua reaksi terhadap masalah ini:
Kata kunci kontekstual membingungkan, mari kita gunakan kembali kata kunci.
Java memiliki banyak kata yang dilindungi undang-undang, beberapa di antaranya tidak digunakan kecuali menyediakan pesan kesalahan yang lebih bermanfaat bagi pemrogram yang beralih ke Java dari C ++. Menambahkan kata kunci baru akan memecah kode. Menambahkan kata kunci kontekstual membingungkan pembaca kode kecuali mereka memiliki penyorotan sintaksis yang baik, dan membuat alat sulit untuk diimplementasikan karena mereka harus menggunakan teknik parsing yang lebih maju (lihat di bawah).
Saat kami ingin memperluas bahasa, satu-satunya pendekatan yang masuk akal adalah menggunakan simbol yang sebelumnya tidak sah dalam bahasa tersebut. Secara khusus, ini tidak bisa menjadi pengidentifikasi. Dengan sintaks foreach loop, Java menggunakan kembali
:
kata kunci yang ada dengan makna baru. Dengan lambdas, Java menambahkan->
kata kunci yang sebelumnya tidak dapat terjadi dalam program hukum apa pun (-->
masih akan lexed sebagai'--' '>'
yang legal, dan->
mungkin sebelumnya telah lexed sebagai'-', '>'
, tetapi urutan itu akan ditolak oleh parser).Kata kunci kontekstual menyederhanakan bahasa, mari kita terapkan
Lexers sangat berguna. Tetapi alih-alih menjalankan lexer sebelum parser, kita dapat menjalankannya bersama-sama dengan parser. Parser bottom-up selalu tahu set tipe token yang akan diterima di lokasi tertentu. Parser kemudian dapat meminta lexer untuk mencocokkan salah satu dari tipe ini pada posisi saat ini. Dalam untuk-setiap loop, parser akan berada pada posisi yang ditunjukkan oleh
·
dalam tata bahasa (disederhanakan) setelah variabel ditemukan:Pada posisi itu, token hukum adalah
SEMICOLON
atauIN
, tetapi tidakIDENT
. Kata kunciin
akan sepenuhnya ambigu.Dalam contoh khusus ini, parser top-down tidak akan memiliki masalah karena kita dapat menulis ulang tata bahasa di atas
dan semua token yang diperlukan untuk keputusan dapat dilihat tanpa mundur.
Pertimbangkan kegunaan
Java selalu cenderung pada kesederhanaan semantik dan sintaksis. Misalnya, bahasa tidak mendukung kelebihan operator karena akan membuat kode jauh lebih rumit. Jadi ketika memutuskan antara
in
dan:
untuk setiap sintaks loop, kita harus mempertimbangkan mana yang kurang membingungkan dan lebih jelas bagi pengguna. Kasus ekstrim mungkin(Catatan: Java memiliki ruang nama terpisah untuk nama jenis, variabel, dan metode. Saya pikir ini adalah kesalahan, sebagian besar. Ini tidak berarti desain bahasa kemudian harus menambahkan lebih banyak kesalahan.)
Alternatif mana yang memberikan pemisahan visual yang lebih jelas antara variabel iterasi dan koleksi iterated? Alternatif mana yang bisa dikenali lebih cepat ketika Anda melihat kode? Saya telah menemukan bahwa memisahkan simbol lebih baik daripada serangkaian kata ketika datang ke kriteria ini. Bahasa lain memiliki nilai yang berbeda. Misalnya Python menguraikan banyak operator dalam bahasa Inggris sehingga mereka dapat dibaca secara alami dan mudah dimengerti, tetapi properti yang sama dapat membuatnya sangat sulit untuk memahami sepotong Python secara sekilas.
sumber
Sintaks loop untuk-setiap ditambahkan di Java 5. Anda harus membuat
in
kata kunci bahasa, dan menambahkan kata kunci ke bahasa nanti adalah sesuatu yang Anda hindari sama sekali karena melanggar kode yang ada - tiba-tiba semua variabel bernamain
menyebabkan penguraian kesalahan.enum
cukup buruk dalam hal itu.sumber
in
akan berarti memperkenalkan kata kunci baru, sehingga melanggar kompatibilitas ke belakang (System.in
, ada orang?) Atau memperkenalkan konsep baru yang sebelumnya tidak dikenal (kata kunci kontekstual). Semua untuk apa untung?for(variable in expression)
tidak pernah dapat ambigu dengan kode hukum apa pun, bahkan jika "in" dapat digunakan untuk variabel. Namun, fase lexer terpisah cukup umum di banyak rangkaian alat penyusun. Ini akan membuat tidak mungkin atau setidaknya jauh lebih sulit untuk mengurai Java dengan beberapa generator pengurai umum. Menyederhanakan sintaksis bahasa biasanya baik untuk semua yang terlibat; tidak semua orang membutuhkan monstrositas sintaksis seperti C ++ atau Perl.const
dangoto
keduanya adalah kata yang dilindungi undang-undang di Jawa, tetapi belum digunakan (belum).