Mengapa titik koma dan koma dipertukarkan untuk loop?

49

Dalam banyak bahasa (daftar yang luas, dari C ke JavaScript):

  • koma ,argumen terpisah (mis. func(a, b, c)), sementara
  • titik koma ;memisahkan instruksi berurutan (misalnya instruction1; instruction2; instruction3).

Jadi mengapa pemetaan ini dibalik dalam bahasa yang sama untuk loop :

for ( init1, init2; condition; inc1, inc2 )
{
    instruction1;
    instruction2;
}

alih-alih (yang tampaknya lebih alami bagi saya)

for ( init1; init2, condition, inc1; inc2 )
{
    instruction1;
    instruction2;
}

?

Tentu, foradalah (biasanya) bukan fungsi, tetapi argumen (yaitu init, condition, increment) berperilaku lebih seperti argumen dari fungsi dari urutan instruksi.

Apakah karena alasan historis / konvensi, atau adakah alasan yang bagus untuk pertukaran ,dan ;dalam perulangan?

Piotr Migdal
sumber
1
(Posting pertama saya di sini. Saya tidak yakin apakah pertanyaan ini milik Pemrogram atau SO, jadi jangan ragu untuk bermigrasi, jika diperlukan.)
Piotr Migdal
8
Ini jelas merupakan posting Programer. Selamat datang! :-)
Martijn Pieters
1
"Mengapa Tidak" akan memberikan jawaban - dengan memiliki jawaban yang sama - "Karena seseorang perlu membuat pilihan, dan itu adalah pilihan yang mereka buat" Sama seperti "Mengapa mereka memilih" {"dan"} "dan 1000 pilihan lainnya mereka membuat - "Karena".
mattnz
2
@ mattnz Pertanyaannya adalah tentang konsistensi (bukan "Mengapa kita ;tidak menggunakan |?" (atau Mengapa kita menggunakan 'lain' bukan 'sebaliknya'? )) yang tidak berlaku untuk satu bahasa, tetapi sejumlah besar dari mereka. Sebuah jawaban yang misalnya "itu dibuat dalam C sebagai singkatan untuk sementara loop (dan beberapa pernyataan untuk inc baru dipikirkan kemudian), dan orang-orang tidak ingin mengubahnya untuk menghindari iritasi programmer" akan baik-baik saja.
Piotr Migdal
Saya ingat pernah membaca - mungkin di dalam K&R - bahwa operator koma pada awalnya ditambahkan ke bahasa agar memungkinkan untuk menginisialisasi lebih dari satu variabel dalam init-ekspresi pernyataan untuk.
zwol

Jawaban:

18

Jadi mengapa dalam bahasa yang sama pemetaan semacam itu dibalik untuk loop.

Secara teknis, pemetaan tidak "terbalik".

  • Hal-hal yang dipisahkan oleh koma bukan parameter. Dalam (setidaknya) C ++ dan Java, mereka bisa berupa deklarasi, jadi itu bahkan bukan ekspresi.
  • Hal-hal yang dipisahkan oleh titik koma juga bukan pernyataan (tunggal).

Pada kenyataannya apa yang kita miliki di sini adalah konteks sintaksis yang berbeda di mana simbol yang sama digunakan secara berbeda. Kami tidak membandingkan suka dengan suka, jadi tidak ada pemetaan, dan tidak ada argumen kuat untuk pemetaan konsisten berdasarkan konsistensi semantik.

Jadi mengapa tidak melakukannya sebaliknya?

Yah saya pikir alasannya datang dari makna "alami" dari ,dan ;. Dalam bahasa tertulis Inggris, tanda titik koma adalah "lebih kuat" istirahat daripada koma, dan mesin terbang untuk tanda koma lebih terlihat daripada koma. Dua hal itu bergabung untuk membuat pengaturan yang sekarang tampak (bagi saya!) Menjadi lebih alami.

Tetapi satu-satunya cara untuk mengetahui dengan pasti mengapa pilihan sintaks dibuat adalah jika desainer C dapat memberi tahu kami apa yang mereka pikirkan pada ~ 1970. Saya ragu mereka memiliki ingatan yang jelas tentang keputusan teknis yang dibuat sejauh itu.


Apakah karena alasan historis / konvensi

Saya tidak mengetahui bahasa apa pun sebelum C yang menggunakan sintaks mirip C untuk loop "for":

  • Donal Fellows mencatat bahwa BCPL dan B tidak memiliki konstruksi yang setara.

  • Setara FORTRAN, COBOL dan Algol-60 (dan Pascal) kurang ekspresif, dan memiliki sintaksis yang tidak menyerupai sintaks C "untuk".

Tetapi bahasa seperti C, C ++ dan Java yang muncul setelah C semuanya dengan jelas meminjam sintaks "untuk" dari C.

Stephen C
sumber
Jadi, filosofi ( ,vs ;) adalah (break lebih lemah vs kuat), bukan (tuple- vs sequence-splitter), kan? Masih bagi saya tidak jelas apakah argumen atau pernyataan membutuhkan jeda yang lebih kuat (seperti dalam banyak kasus untuk urutan pernyataan, jeda adalah implisit (lihat misalnya JavaScript (misalnya i++[line break]j++))), tetapi setidaknya sekarang saya mendapatkan poin mengapa konvensi saat ini tidak "jelas terbalik".
Piotr Migdal
@PiotrMigdal, koma sebagai pembatas akan mencegah penggunaan koma operan dan mungkin menyiratkan komponen dari for loop adalah pernyataan daripada ekspresi. Ini memiliki implikasi yang signifikan.
Komentar terakhir membuat saya penasaran apa yang dilakukan BCPL, tetapi ternyata ada FOR i = e1 TO e2 BY e3 DO c(ekspresi e1..e3, perintah c), yang lebih mirip dengan sintaksis BASIC. Sumber
CVn
1
@PiotrMigdal - "Filsafat" adalah apa pun yang dilakukan oleh K&R dan yang lainnya berpikir kembali pada tahun 1970. Saya tidak berpikir itu masuk ke kedalaman pemikiran yang Anda bayangkan. (Mereka mencoba menerapkan bahasa "tingkat yang lebih tinggi" untuk menghindari keharusan menulis banyak perangkat lunak sakelar telepon dalam assembler.)
Stephen C
Aku baru saja memeriksa; yang forsintaks diperkenalkan di C (bukan di B atau BCPL).
Donal Fellows
60

Kami menulis loop seperti:

 for(x = 0; x < 10; x++)

Bahasanya bisa didefinisikan sehingga loop tampak seperti:

 for(x = 0, x < 10, x++)

Namun, pikirkan loop yang sama diimplementasikan menggunakan loop sementara:

 x = 0;
 while(x < 10)
 {
     x++;
 }

Perhatikan bahwa pernyataan x=0dan x++adalah, diakhiri dengan titik koma. Mereka bukan ekspresi seperti yang akan Anda miliki dalam panggilan fungsi. Titik koma digunakan untuk memisahkan pernyataan, dan karena dua dari tiga elemen dalam for for adalah pernyataan, itulah yang digunakan di sana. A for loop hanyalah jalan pintas untuk loop sementara.

Selain itu, argumen tidak benar-benar bertindak seperti argumen untuk suatu fungsi. Yang kedua dan ketiga dievaluasi berulang kali. Memang benar mereka tidak berurutan, tetapi mereka juga bukan argumen fungsi.

Juga, fakta bahwa Anda dapat menggunakan koma untuk memiliki banyak pernyataan dalam for for sebenarnya adalah sesuatu yang bisa Anda lakukan di luar for for.

x = 0, y= 3;

adalah pernyataan yang benar-benar valid bahkan di luar for for loop. Saya tidak tahu adanya penggunaan praktis di luar for loop. Tetapi intinya adalah bahwa koma selalu membagi pernyataan; ini bukan fitur khusus dari for loop.

Winston Ewert
sumber
Tentu, saya mengerti bahwa "while" loop "lebih mendasar". Tapi "notasi tangan pendek" semacam itu tidak masuk akal (setidaknya bagi saya), karena Anda bisa mulai dengan x = 0; y = 0;dan (di dalam kurung keriting) x++; y++;...
Piotr Migdal
2
@PiotrMigdal, oh Anda bisa. Maksud saya adalah bahwa bagian-bagian di dalam for loop adalah pernyataan (yang dipisahkan dengan titik koma) bukan ekspresi (yang dipisahkan oleh koma)
Winston Ewert
1
Saya mendapatkan perbedaan, hanya bagi saya ;adalah alami untuk urutan pernyataan , tidak harus memisahkan pernyataan apa pun (jadi apakah hanya rasanya berbeda?). Dan dalam konvensi saat ini, seseorang kadang-kadang berakhir dengan memisahkan urutan pernyataan dengan koma ...
Piotr Migdal
3
@PiotrMigdal, anggota struct / serikat dipisahkan oleh titik koma, tetapi mereka tidak benar-benar berurutan. Jadi tentu saja tidak terbatas pada urutan pernyataan dalam penggunaannya. Di akhir hari, sintaksisnya lebih terasa.
Winston Ewert
Saya tidak tahu ada penggunaan praktis di luar for loop --- Bagaimana kalau (foo)?bar++, qux++:bletch--- Di mana Anda ingin ?:ekspresi melakukan dua hal, bukan hanya satu. Nilai kembali jika fooitu benar qux, tetapi keduanya bardan quxbertambah.
15

Dalam C dan C ++ ini adalah operator koma, bukan hanya koma.

Tata bahasanya foradalah seperti

for ([pre-expression]; [terminate-condition]; [increment-expression]) body-expression

Dalam hal pertanyaan Anda:

pre-expression -> init1, init2
terminate-condition -> condition
increment-expression -> inc1, inc2

Perhatikan bahwa operator-koma memungkinkan Anda untuk melakukan beberapa tindakan dalam satu pernyataan (seperti yang dilihat kompilator). Jika saran Anda diimplementasikan akan ada ambiguitas dalam tata bahasa ketika programmer berniat untuk menulis pernyataan koma-operator atau pemisah.

Singkatnya, ;menandakan akhir dari sebuah pernyataan. Sebuah forlingkaran adalah kata kunci diikuti dengan daftar pernyataan opsional dikelilingi oleh (). Pernyataan koma-operator memungkinkan penggunaan ,dalam satu pernyataan.

James
sumber
3
A for loop adalah sekumpulan ekspresi yang dipisahkan oleh titik koma. Pernyataan bisa lebih dari sekadar ekspresi - seseorang tidak bisa memasukkan pernyataan kasus atau jika pernyataan menjadi bagian for for. Ini adalah implikasi yang signifikan untuk mengatakan bahwa komponen dari for loop adalah pernyataan ketika seseorang melihat bentuk
@MichaelT: Tetapi dalam C ++ sintaksis dari forloop secara eksplisit memungkinkan pernyataan (deklarasi) sebagai bagian pertama. (C ++ memungkinkan deklarasi fungsi-tengah, sebagai lawan dari pendahulunya C89). Anda tidak dapat menggeneralisasikan pernyataan seperti itu di seluruh bahasa, bahkan untuk 2 bahasa yang sedekat C dan C ++.
MSalters
@MichaelT Apakah Anda melewatkan bagian 'sesuatu seperti'?
James
@James Anda dapat menghindari "sesuatu seperti" dengan menggunakan bnf aktual for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>untuk C dan for ( for-init-statement; conditionopt ; expressionopt ) statementuntuk C ++ --- The ';' tidak hanya menandakan terminator pernyataan. A untuk loop tidak diikuti oleh pernyataan terlampir dalam ().
8

Tidak ada pembalikan konseptual.

Titik koma di C mewakili lebih banyak divisi utama daripada koma. Mereka memisahkan pernyataan dan deklarasi.

Divisi utama dalam for loop adalah bahwa ada tiga ekspresi (atau deklarasi dan dua ekspresi) dan sebuah badan.

Koma yang Anda lihat di C untuk loop bukan bagian dari sintaks for for loop secara khusus. Mereka hanya manifestasi dari operator koma.

Koma adalah pemisah utama antara argumen dalam panggilan fungsi dan antara parameter dalam deklarasi fungsi, tetapi titik koma tidak digunakan. Untuk loop adalah sintaks khusus; itu tidak ada hubungannya dengan fungsi atau panggilan fungsi.

Kaz
sumber
2

Mungkin ini adalah sesuatu yang spesifik untuk C / C ++, tetapi saya memposting jawaban ini, karena sintaks dari bahasa yang Anda jelaskan sebagian besar dipengaruhi oleh Sintaks C-.

Selain pertanyaan yang dijawab sebelumnya benar, dari sudut pandang teknis, itu juga karena dalam C (dan C ++) koma sebenarnya adalah operator , yang Anda bahkan dapat membebani . Menggunakan operator titik koma ( operator;()) mungkin akan membuat lebih sulit untuk menulis kompiler, karena titik koma adalah terminator ekspresi aksiomatik.

Apa yang membuat titik-temu ini adalah fakta, bahwa koma banyak digunakan sebagai pemisah di seluruh bahasa. Sepertinya operator koma adalah pengecualian, yang terutama digunakan untuk mendapatkan for-lompatan dengan beberapa kondisi bekerja, jadi apa masalahnya?

Sebenarnya operator,dibangun untuk melakukan hal yang sama seperti dalam definisi, daftar argumen, dan sebagainya: Telah dibangun untuk memisahkan ekspresi - sesuatu yang ,tidak dapat dilakukan oleh konstruksi sintaksis . Ini hanya dapat memisahkan apa yang telah didefinisikan dalam standar.

Namun titik koma tidak terpisah - itu berakhir . Dan ini juga yang membawa kita kembali ke pertanyaan awal:

for (int a = 0, float b = 0.0f; a < 100 && b < 100.0f; a++, b += 1.0f)
    printf("%d: %f", a, b);

Koma memisahkan ekspresi dalam tiga bagian loop, sedangkan titik koma mengakhiri bagian (inisialisasi, kondisi atau afterthought) dari definisi loop.

Bahasa pemrograman yang lebih baru (seperti C #) mungkin tidak memungkinkan overloading koma-operator, tetapi mereka kemungkinan besar tetap menggunakan sintaksis, karena mengubahnya terasa agak tidak wajar.

Aschratt
sumber
Ada masalah dengan argumen ini. Dalam sebuah forpernyataan, ;simbol digunakan sebagai pemisah. Ini memisahkan 3 bagian sintaksis dari pernyataan itu. Tidak ada titik koma ke-3 untuk "mengakhiri" daftar ekspresi progresif. Ini diakhiri oleh token yang berbeda - ).
Stephen C
0

Bagi saya mereka menggunakan makna yang kurang lebih mirip dengan arti linguistik mereka. Koma digunakan dengan daftar dan titik koma dengan bagian yang lebih terpisah.

Dalam func(a, b, c)kami memiliki daftar argumen.

instruction1; instruction2; instruction3 mungkin daftar tetapi daftar instruksi yang terpisah dan independen.

Sementara di for ( init1, init2; condition; inc1, inc2 )kami memiliki tiga bagian terpisah - daftar inisialisasi, kondisi dan daftar ekspresi kenaikan.

ludwika
sumber
0

Cara termudah untuk melihatnya adalah sebagai berikut:

for(x = 0; x < 10; x++)

aku s:

for(
x = 0;
x < 10;
x++
)

Dengan kata lain, mereka x = 0 thingy sebenarnya adalah pernyataan / instruksi daripada parameter. Anda memasukkan pernyataan di sana. Karenanya mereka dipisahkan oleh titik koma.

Bahkan tidak mungkin mereka dipisahkan oleh koma. Kapan terakhir kali Anda memasukkan hal-hal seperti x <10 sebagai parameter? Anda melakukannya jika Anda ingin komputer x <10 sekali dan masukkan hasil operasi itu sebagai parameter. Jadi di dunia koma Anda akan meletakkan x <10 jika Anda ingin meneruskan nilai x <0 ke suatu fungsi.

Di sini Anda menentukan bahwa program harus memeriksa x <10 setiap kali loop dilewatkan. Jadi itu instruksi.

x ++ jelas merupakan instruksi lain.

Itu semua instruksi. Jadi mereka dipisahkan oleh titik koma.

pengguna4951
sumber
Itu bukan pernyataan. Ini adalah ekspresi yang dipisahkan oleh tanda titik koma. Sebuah pernyataan sangat berbeda.
x <10 dapat berupa ekspresi (yang biasanya dipisahkan dengan tanda titik koma. x = 0 jelas merupakan pernyataan / instruksi.
user4951
Lihatlah bnf untuk C - jika loop for adalah pernyataan, seseorang dapat menggunakan pernyataan lain seperti yang lain for switchatau return di dalam definisi loop (yaitu for(int i = 0; if(i > 1024) { return; } ; switch (i % 3) { case 0; case 1: i++; case 2: i++; } ) { ... }) --- Anda tidak bisa. Itu bukan pernyataan. Sebaliknya itu didefinisikan sebagaifor ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>
Aneh. int i = 0 adalah ekspresi baik-baik saja, tetapi kami melakukannya terutama untuk menyatakan int yaitu i dan menetapkan 0 untuk itu (itu juga mengembalikan 0 tetapi sebagai efek samping. Anda tidak dapat melakukannya untuk ({int i = 0; j = i}; j <0; cout << "Halo dunia") bisakah Anda? Atau ya saya pikir Anda bisa.
user4951
1
@ Jim Jio: Anda mungkin tidak menyadarinya, tetapi "pernyataan" dan "ekspresi" memiliki arti yang sangat tepat dalam standar bahasa. int i = 0pasti BUKAN ekspresi. Seperangkat aturan yang menggambarkan ekspresi cukup rumit, mengingat apa yang bisa membentuk ekspresi, tetapi konstruk TYPE NAME = EXPRESSIONtidak cocok dengan aturan itu.
MSalters