Mengapa masing-masing memiliki titik dua bukan “di”?

9

Dari panduan bahasa Java 5 :

Ketika Anda melihat titik dua (:) membacanya sebagai "dalam".

Mengapa tidak menggunakan initu saja?

Ini telah menggangguku selama bertahun-tahun. Karena itu tidak konsisten dengan sisa bahasa. Misalnya, di Jawa ada implements, extends, superuntuk 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: elementsatau 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 insejauh 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 intidak membawa kompleksitas tambahan atau memerlukan kata kunci baru.

pengguna2418306
sumber
1
Sumber terbaik untuk mengetahui motivasi dari perancang bahasa seringkali adalah perancang itu sendiri. Yang mengatakan, ini tampaknya hanya gula sintaksis di atas iterable; lihat stackoverflow.com/questions/11216994/...
Robert Harvey

Jawaban:

8

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:

FOR = 'for'
LPAREN = '('
RPAREN = ')'
IN = 'in'
IDENT = /\w+/
COLON = ':'
SEMICOLON = ';'

Tokenizer akan selalu cocok dengan token terpanjang, dan lebih suka kata kunci daripada pengidentifikasi. Jadi interestingakan digambarkan sebagai IDENT:interesting, tetapi inakan digambarkan sebagai IN, tidak pernah sama IDENT:interesting. Seperti cuplikan kode

for(var in expression)

akan diterjemahkan ke aliran token

FOR LPAREN IDENT:var IN IDENT:expression RPAREN

Sejauh ini, itu berhasil. Tetapi variabel apa pun inakan lexed sebagai kata kunci INdaripada variabel, yang akan memecahkan kode. Lexer tidak menyimpan status apa pun di antara token, dan tidak dapat mengetahui bahwa inbiasanya merupakan variabel kecuali saat kita berada dalam for for loop. Juga, kode berikut ini harus legal:

for(in in expression)

Yang pertama inakan 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:

for_loop = for_loop_cstyle | for_each_loop
for_loop_cstyle = 'for' '(' declaration · ';' expression ';' expression ')'
for_each_loop = 'for' '(' declaration · 'in' expression ')'

Pada posisi itu, token hukum adalah SEMICOLONatau IN, tetapi tidak IDENT. Kata kunci inakan sepenuhnya ambigu.

Dalam contoh khusus ini, parser top-down tidak akan memiliki masalah karena kita dapat menulis ulang tata bahasa di atas

for_loop = 'for' '(' declaration · for_loop_rest ')'
for_loop_rest =  · ';' expression ';' expression
for_loop_rest = · 'in' expression

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 indan :untuk setiap sintaks loop, kita harus mempertimbangkan mana yang kurang membingungkan dan lebih jelas bagi pengguna. Kasus ekstrim mungkin

for (in in in in())
for (in in : in())

(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.

amon
sumber
17

Sintaks loop untuk-setiap ditambahkan di Java 5. Anda harus membuat inkata 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 bernama in menyebabkan penguraian kesalahan. enumcukup buruk dalam hal itu.

Michael Borgwardt
sumber
2
Sepertinya ... tidak nyaman. Ini mengandaikan perancang bahasa cukup baik untuk memperkirakan sebagian besar kata kunci yang diperlukan dari awal. Saya tidak yakin itu perlu; kompiler yang layak dapat menentukan apakah suatu kata kunci merupakan variabel berdasarkan konteksnya atau tidak.
Robert Harvey
2
Saya tidak berpikir Java memiliki kata kunci kontekstual seperti yang dimiliki C #. Jadi, menggunakan inakan 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?
Jörg W Mittag
2
Apa salahnya kata kunci kontekstual?
user2418306
5
@ user2418306 Menambahkan kata kunci tidak harus memecah kode yang ada, asalkan bahasa tidak diuraikan dengan fase lexer terpisah. Secara khusus, sebuah "in" in 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.
amon
1
@RobertHarvey: Jangan lupa itu constdan gotokeduanya adalah kata yang dilindungi undang-undang di Jawa, tetapi belum digunakan (belum).
TMN