Dalam perangkat lunak, alur kendali (atau aliran kendali) menjelaskan bagaimana eksekusi berpindah dari satu perintah ke perintah berikutnya. Dalam banyak konteks, seperti kode mesin dan bahasa pemrograman imperatif, kendali berlangsung secara berurutan (menuju perintah yang terletak tepat setelah perintah yang sedang dieksekusi), kecuali ketika sebuah perintah memindahkan kendali ke titik lain — dalam hal ini perintah tersebut diklasifikasikan sebagai perintah alur kendali. Bergantung pada konteksnya, istilah lain dapat digunakan sebagai pengganti perintah. Misalnya, dalam kode mesin, istilah yang lazim digunakan adalah instruksi, sedangkan dalam bahasa imperatif, istilah yang lazim digunakan adalah pernyataan.
Meskipun bahasa imperatif mengodekan alur kendali secara eksplisit, bahasa dengan paradigma pemrograman lain tidak terlalu berfokus pada alur kendali. Bahasa deklaratif menentukan hasil yang diinginkan tanpa menetapkan urutan operasi. Bahasa fungsional menggunakan konstruksi bahasa dan fungsi untuk mengendalikan alur, meskipun biasanya konstruksi tersebut tidak disebut sebagai pernyataan alur kendali.
Dalam unit pemrosesan pusat set instruksi, instruksi alur kendali sering mengubah program counter dan berupa percabangan tanpa syarat (disebut juga lompatan) atau percabangan bersyarat. Pendekatan alternatif adalah predikasi, yang mengaktifkan instruksi secara bersyarat alih-alih melakukan percabangan.
Pemindahan alur kendali asinkron, seperti interupsi atau sinyal, mengubah alur kendali normal menuju sebuah penangan sebelum mengembalikan kendali ke tempat ketika alur tersebut diinterupsi.
Salah satu cara untuk menyerang perangkat lunak adalah dengan mengalihkan alur eksekusi. Berbagai teknik control-flow integrity, termasuk stack canary, perlindungan buffer overflow, shadow stack, dan verifikasi penunjuk vtable, digunakan untuk bertahan terhadap serangan tersebut.[1][2][3]
Struktur
Alur kendali berkaitan erat dengan struktur kode. Alur kendali mengikuti jalur yang ditentukan oleh struktur dan aturan eksekusi suatu bahasa. Konsep umum mengenai struktur ini tidak boleh disamakan dengan pemrograman terstruktur, yang membatasi struktur pada pengurutan, seleksi, dan iterasi berdasarkan organisasi blok.
Urutan
Eksekusi berurutan merupakan struktur yang paling dasar. Meskipun tidak semua kode bersifat berurutan, kode imperatif bersifat demikian.
Label
Sebuah label mengidentifikasi suatu posisi dalam kode sumber. Beberapa pernyataan alur kendali merujuk pada label sehingga kendali dapat melompat ke baris yang diberi label. Selain menandai suatu posisi, label tidak memiliki efek lain.
Beberapa bahasa membatasi label hanya pada angka yang terkadang disebut nomor baris, meskipun istilah tersebut menyiratkan indeks bawaan dari baris tersebut, bukan sebuah label. Meskipun demikian, label numerik seperti ini biasanya diwajibkan meningkat dari atas ke bawah dalam sebuah berkas, meskipun tidak harus berurutan. Misalnya, dalam BASIC:
10LETX=3 20PRINTX 30GOTO10
Dalam banyak bahasa, label merupakan pengenal alfanumerik, biasanya muncul di awal baris dan langsung diikuti titik dua. Misalnya, kode C berikut mendefinisikan label Success pada baris 3 yang mengidentifikasi titik tujuan lompatan pada pernyataan pertama yang mengikutinya (baris 4).
voidf(boolok){ if(ok){ gotosuccess; } return; success: printf("OK"); }
Blok
Sebagian besar bahasa menyediakan cara untuk mengorganisasikan urutan kode sebagai sebuah blok. Ketika digunakan bersama pernyataan kendali, awal sebuah blok menyediakan tujuan lompatan. Misalnya, pada kode C berikut (yang menggunakan kurung kurawal untuk membatasi sebuah blok), kendali melompat dari baris 1 ke baris 4 jika done bernilai false.
if(done){ printf("All done"); }else{ printf("Still workin' on it"); }
Kendali
Banyak perintah kendali telah dirancang untuk bahasa pemrograman. Bagian ini menjelaskan konstruksi yang penting dan diorganisasikan berdasarkan fungsinya.
Fungsi
Sebuah fungsi menyediakan alur kendali karena ketika dipanggil, eksekusi melompat ke awal kode fungsi tersebut dan ketika fungsi selesai, kendali kembali ke titik pemanggilannya. Dalam kode C berikut, kendali melompat dari baris 6 ke baris 2 untuk memanggil fungsi foo(). Kemudian, setelah tubuh fungsi selesai (mencetak "Hi"), kendali kembali ke setelah pemanggilan, yaitu baris 7.
voidfoo(){ printf("Hi"); } voidbar(){ foo(); printf("Done"); }
Percabangan
Perintah percabangan memindahkan titik eksekusi dari titik dalam kode yang memuat perintah tersebut ke titik yang ditentukan oleh perintah.
Lompatan
Perintah lompatan secara tidak bersyarat melakukan percabangan kendali ke titik lain dalam kode, dan merupakan bentuk paling dasar untuk mengendalikan alur kode.
Dalam bahasa tingkat tinggi, hal ini sering disediakan sebagai pernyataan goto. Meskipun kata kunci tersebut dapat ditulis dengan huruf besar atau kecil atau terdiri dari satu atau dua kata, bergantung pada bahasanya, bentuknya seperti: goto label. Ketika kendali mencapai pernyataan goto, kendali kemudian melompat ke pernyataan setelah label yang ditunjukkan. Pernyataan goto telah dianggap berbahaya oleh banyak ilmuwan komputer, termasuk Dijkstra.
Percabangan bersyarat
Pernyataan bersyarat memindahkan kendali berdasarkan nilai suatu ekspresi Boolean. Variasi yang umum meliputi:
- if-goto
- Melompat ke sebuah label berdasarkan suatu kondisi; pernyataan pemrograman tingkat tinggi yang sangat menyerupai instruksi kode mesin yang sejenis
- if-then
- Alih-alih terbatas pada lompatan, sebuah pernyataan atau blok dieksekusi jika ekspresi bernilai benar. Dalam bahasa yang tidak memiliki kata kunci
then, konstruksi ini dapat disebut pernyataan if.
- if-then-else
- Seperti if-then, tetapi dengan tindakan kedua yang dilakukan jika kondisi bernilai salah. Dalam bahasa yang tidak memiliki kata kunci
then, konstruksi ini dapat disebut pernyataan if-else.
- Bersarang
- Pernyataan bersyarat sering ditempatkan di dalam pernyataan bersyarat lainnya.
- if aritmetika
- Fortran awal memiliki if aritmetika (disebut juga if tiga arah) yang menguji apakah suatu nilai numerik negatif, nol, atau positif. Pernyataan ini dinyatakan usang dalam Fortran-90 dan dihapus sejak Fortran 2018.
- Operator
- Beberapa bahasa memiliki bentuk operator, seperti operator kondisional ternary.
- When dan unless
- Perl melengkapi
ifbergaya C denganwhendanunless.
- Pesan
- Smalltalk menggunakan pesan
ifTruedanifFalseuntuk mengimplementasikan kondisi, bukan konstruksi bahasa.
Kode Pascal berikut menunjukkan if-then-else sederhana. Sintaksnya mirip dengan Ada:
ifa>0then writeln("yes") else writeln("no");
Dalam C:
if(a>0){ puts("yes"); }else{ puts("no"); }
Dalam bash:
if[$a-gt0];then echo"yes" else echo"no" fi
Dalam Python:
if a > 0: print("yes") else: print("no")
Dalam Lisp:
(princ (if(pluspa) "yes" "no"))
Percabangan multiarah
Percabangan multiarah memindahkan kendali berdasarkan pencocokan nilai. Biasanya tersedia tindakan bawaan jika tidak ditemukan kecocokan. Sebuah pernyataan switch dapat memungkinkan pengoptimalan oleh kompiler, seperti tabel pencarian. Dalam bahasa dinamis, kasus mungkin tidak terbatas pada ekspresi konstan dan dapat diperluas ke pencocokan pola, seperti pada contoh shell script di sebelah kanan, yang menggunakan *) untuk mengimplementasikan kasus bawaan sebagai glob yang cocok dengan string apa pun. Logika case juga dapat diimplementasikan dalam bentuk fungsional, seperti pernyataan decode dalam SQL.
Kode Pascal berikut menunjukkan pernyataan switch yang relatif sederhana. Pascal menggunakan kata kunci case alih-alih switch.
casesomeCharof 'a':actionOnA; 'x':actionOnX; 'y','z':actionOnYandZ; elseactionOnNoMatch; end;
Dalam Ada:
case someChar is when 'a' => actionOnA; when 'x' => actionOnX; when 'y' | 'z' => actionOnYandZ; when others => actionOnNoMatch; end;
Dalam C:
switch(someChar){ case'a': actionOnA; break; case'x': actionOnX; break; case'y': case'z': actionOnYandZ; break; default: actionOnNoMatch; }
Dalam Bash:
case$someCharin a)actionOnA;; x)actionOnX;; [yz])actionOnYandZ;; *)actionOnNoMatch;; esac
Dalam Lisp:
(casesome-char ((#\a)action-on-a) ((#\x)action-on-x) ((#\y#\z)action-on-y-and-z) (elseaction-on-no-match))
Dalam Fortran:
select case(someChar) case('a') actionOnA case('x') actionOnX case('y','z') actionOnYandZ case default actionOnNoMatch end select
Perulangan

Dalam suatu perulangan, urutan pernyataan—yang sering disebut sebagai tubuh perulangan—dieksekusi kembali (setidaknya sebagian) setelah percabangan bersyarat atau lompatan ke langkah sebelumnya dalam urutan tersebut. Jumlah eksekusi suatu perulangan biasanya bergantung pada keadaan saat runtime, misalnya: tubuh dieksekusi sekali untuk setiap item dalam suatu koleksi (iterasi pasti), hingga suatu kondisi terpenuhi (iterasi tak pasti). Namun, beberapa perulangan dapat berulang tanpa batas. Sebuah perulangan dapat ditulis sebagai perulangan tak terbatas, tetapi keluarnya dari perulangan dikendalikan oleh pengujian di dalam tubuh perulangan yang memindahkan kendali ke luar perulangan. Keluar lebih awal dari suatu perulangan dapat didukung melalui pernyataan break.[4][5]
Perulangan yang berada di dalam tubuh perulangan lain disebut perulangan bersarang.[6][7][8]
Dalam bahasa pemrograman fungsional, seperti Haskell dan Scheme, proses rekursif maupun iteratif diekspresikan dengan prosedur rekursif ekor alih-alih konstruksi perulangan yang bersifat sintaksis.
Numerik
Perulangan yang relatif sederhana tetapi berguna melakukan iterasi pada rentang nilai numerik. Bentuk sederhana dimulai dari suatu nilai bilangan bulat, berakhir pada nilai bilangan bulat yang lebih besar, dan melakukan iterasi untuk setiap nilai bilangan bulat di antaranya. Sering kali, kenaikan dapat berupa bilangan bulat apa pun (bahkan negatif, untuk melakukan perulangan dari nilai yang lebih besar ke nilai yang lebih kecil).
Contoh dalam BASIC:
FORI=1TON xxx NEXTI
Contoh dalam Pascal:
forI:=1toNdobegin xxx end;
Contoh dalam Fortran:
DO I=1,N xxx END DO
Dalam banyak bahasa pemrograman, hanya bilangan bulat yang dapat digunakan atau dapat digunakan secara andal. Karena bilangan titik mengambang direpresentasikan secara tidak tepat akibat keterbatasan perangkat keras, perulangan berikut dapat melakukan iterasi sebanyak 9 atau 10 kali, bergantung pada berbagai faktor seperti galat pembulatan, perangkat keras, dan kompiler. Selain itu, jika kenaikan X dilakukan melalui penjumlahan berulang, galat pembulatan yang terakumulasi dapat menyebabkan nilai X pada setiap iterasi berbeda cukup jauh dari urutan yang biasanya diharapkan, yaitu 0.1, 0.2, 0.3, ..., 1.0.
for X := 0.1 step 0.1 to 1.0 do
Dikendalikan kondisi
Beberapa konstruksi perulangan melakukan iterasi hingga suatu kondisi bernilai benar. Beberapa variasi menguji kondisi pada awal perulangan; yang lain mengujinya pada akhir. Jika pengujian dilakukan di awal, tubuh perulangan dapat dilewati sepenuhnya. Jika dilakukan di akhir, tubuh perulangan selalu dieksekusi setidaknya sekali.
Contoh dalam Visual Basic:
DOWHILE(test) xxx LOOP
Contoh dalam Pascal:
repeat xxx untiltest;
Contoh pra-pengujian dalam keluarga C:
while(test){ xxx }
Contoh pascapengujian dalam keluarga C:
do xxx while(test);
Meskipun menggunakan kata kunci for, perulangan C bergaya tiga bagian merupakan konstruksi berbasis kondisi, bukan berbasis numerik. Bagian kedua, yaitu kondisi, dievaluasi sebelum setiap perulangan, sehingga merupakan pra-pengujian. Bagian pertama merupakan tempat untuk menginisialisasi keadaan, sedangkan bagian ketiga digunakan untuk melakukan kenaikan pada iterasi berikutnya, tetapi kedua aspek tersebut dapat dilakukan di tempat lain. Kode C berikut mengimplementasikan logika perulangan numerik yang melakukan iterasi untuk i dari 0 hingga n-1.
for(inti=0;i<n;++i){ xxx }
Enumerasi
Beberapa konstruksi perulangan melakukan enumerasi item dalam suatu koleksi; melakukan iterasi untuk setiap item.
Contoh dalam Smalltalk:
someCollection do: [:eachElement |xxx].
Contoh dalam Pascal:
forIteminCollectiondobeginxxxend;
Contoh dalam Raku:
foreach (item; myCollection) { xxx }
Contoh dalam TCL:
foreachsomeArray{xxx}
Contoh dalam PHP:
foreach ($someArray as $k => $v) { xxx }
Contoh dalam Java:
Collection<String>coll; for(Strings:coll){}
Contoh dalam C#:
foreach(stringsinmyStringCollection){xxx}
Contoh dalam PowerShell, dengan 'foreach' sebagai alias dari 'ForEach-Object':
someCollection | foreach { $_ }
Contoh dalam Fortran:
forall(index=first:last:step...)
Scala memiliki ekspresi for, yang menggeneralisasi perulangan yang dikendalikan oleh koleksi dan juga mendukung penggunaan lain, seperti pemrograman asinkron. Haskell memiliki ekspresi do dan komprehensi, yang secara bersama-sama menyediakan fungsi yang serupa dengan ekspresi for dalam Scala.
Tak terbatas
Masalah loop-and-a-half
Struktur perulangan umum terkadang menghasilkan kode yang terduplikasi, baik berupa pernyataan yang diulang maupun kondisi yang diulang. Hal ini muncul karena berbagai alasan dan terdapat berbagai solusi yang diusulkan untuk menghilangkan atau meminimalkan duplikasi kode.[9] Selain solusi tradisional yang tidak terstruktur berupa pernyataan goto,[10] solusi terstruktur yang umum mencakup menempatkan kondisi (pernyataan if) di dalam perulangan (yang mungkin menduplikasi kondisi tetapi tidak pernyataan) atau membungkus logika yang berulang dalam suatu fungsi (sehingga terjadi duplikasi pemanggilan fungsi, tetapi bukan duplikasi pernyataan).[9]
Kasus umum terjadi ketika awal perulangan selalu dieksekusi, tetapi bagian akhir dapat dilewati pada iterasi terakhir.[10] Hal ini disebut oleh Dijkstra sebagai perulangan yang dilakukan "n setengah kali",[11] dan sekarang disebut masalah loop-and-a-half.[5] Kasus umum mencakup membaca data pada bagian pertama, memeriksa akhir data, lalu memproses data pada bagian kedua; atau melakukan pemrosesan, memeriksa akhir, lalu menyiapkan iterasi berikutnya.[10][5] Dalam kasus tersebut, bagian pertama perulangan dieksekusi sebanyak
n
{\displaystyle n}
kali, tetapi bagian kedua hanya dieksekusi sebanyak
n
−
1
{\displaystyle n-1}
kali.
Masalah ini telah dikenali setidaknya sejak 1967 oleh Knuth, dengan Wirth menyarankan penyelesaiannya melalui penghentian perulangan lebih awal.[12] Sejak 1990-an, solusi yang paling umum diajarkan menggunakan pernyataan break, seperti:
loop
statements
if condition break
statements
repeat
Hal yang perlu diperhatikan dari solusi ini adalah bahwa kondisi tersebut merupakan kebalikan dari kondisi while biasa: menulis ulang while condition ... repeat dengan keluar di tengah mengharuskan kondisi dibalik: loop ... if not condition exit ... repeat. Struktur kendali perulangan dengan pengujian di tengah secara eksplisit mendukung kasus loop-and-a-half, tanpa membalik kondisi.[12]
Tidak terstruktur
Sebuah konstruksi perulangan menyediakan kriteria penyelesaian terstruktur yang menghasilkan iterasi berikutnya atau melanjutkan eksekusi setelah pernyataan perulangan. Namun, berbagai konstruksi alur kendali tidak terstruktur didukung oleh banyak bahasa.
- Iterasi berikutnya lebih awal
- Beberapa bahasa menyediakan konstruksi yang memindahkan kendali ke awal tubuh perulangan untuk iterasi berikutnya; misalnya,
continue(yang paling umum),skip,[13]cycle(Fortran), ataunext(Perl dan Ruby).
- Mengulangi iterasi
- Beberapa bahasa, seperti Perl[14] dan Ruby,[15] memiliki pernyataan
redoyang melompat ke awal tubuh untuk iterasi yang sama.
- Mulai ulang
- Ruby memiliki pernyataan
retryyang memulai ulang seluruh perulangan dari iterasi pertama.[16]
Keluar lebih awal
Keluar lebih awal memindahkan kendali ke setelah tubuh perulangan.[17][5] Misalnya, ketika mencari suatu daftar, perulangan dapat dihentikan ketika item ditemukan. Beberapa bahasa menyediakan pernyataan seperti break (sebagian besar bahasa), Exit (Visual Basic), atau last (Perl).
Dalam kode Ada berikut, perulangan berhenti ketika X bernilai 0.
loop Get(X); if X = 0 then exit; end if; DoSomething(X); end loop;
Gaya yang lebih idiomatis menggunakan exit when:
loop Get(X); exit when X = 0; DoSomething(X); end loop;
Python mendukung eksekusi kode secara kondisional bergantung pada apakah suatu perulangan dihentikan lebih awal (dengan pernyataan break) atau tidak, dengan menggunakan klausa else pada perulangan. Dalam kode Python berikut, klausa else terkait dengan pernyataan for, bukan pernyataan if di dalamnya. Baik perulangan for maupun while Python mendukung klausa else tersebut, yang hanya dieksekusi jika perulangan tidak dihentikan lebih awal.
for n in set_of_numbers: if isprime(n): print("Set contains a prime number") break else: print("Set did not contain any prime numbers")
Break bertingkat
Beberapa bahasa mendukung penghentian perulangan bersarang; dalam teori sirkuit, ini disebut break bertingkat. Salah satu penggunaan umum adalah pencarian pada tabel multidimensi. Hal ini dapat dilakukan melalui break multitingkat (keluar dari
N
{\displaystyle N}
tingkat), seperti dalam bash[18] dan PHP,[19] atau melalui break berlabel (keluar dan melanjutkan pada label tertentu), seperti dalam Ada, Go, Java, Rust, dan Perl.[20] Alternatif untuk break multitingkat meliputi break tunggal bersama variabel keadaan yang diuji untuk keluar dari tingkat lain; pengecualian yang ditangkap pada tingkat tempat keluarnya dilakukan; menempatkan perulangan bersarang dalam sebuah fungsi dan menggunakan return untuk menghentikan seluruh perulangan bersarang; atau menggunakan label dan pernyataan goto. C maupun C++ saat ini tidak memiliki break multitingkat atau perulangan bernama, dan alternatif yang umum adalah menggunakan goto untuk mengimplementasikan break berlabel.[21] Namun, penambahan fitur ini telah diusulkan,[22] dan ditambahkan ke C29,[23] mengikuti sintaks Java. Python tidak memiliki break atau continue multitingkat — fitur ini diusulkan dalam PEP 3136 dan ditolak karena kompleksitas tambahan dianggap tidak sebanding dengan penggunaan sah yang jarang terjadi.[24]
Gagasan mengenai break bertingkat menarik dalam ilmu komputer teoretis, karena menghasilkan apa yang sekarang disebut hierarki Kosaraju.[25] Pada 1973 S. Rao Kosaraju menyempurnakan teorema program terstruktur dengan membuktikan bahwa variabel tambahan dapat dihindari dalam pemrograman terstruktur selama break bertingkat dengan kedalaman arbitrer diperbolehkan.[26] Selain itu, Kosaraju membuktikan bahwa terdapat hierarki program yang ketat: untuk setiap bilangan bulat
n
{\displaystyle n}
, terdapat program yang mengandung break bertingkat dengan kedalaman
n
{\displaystyle n}
yang tidak dapat ditulis ulang sebagai program dengan break bertingkat berkedalaman kurang dari n tanpa menambahkan variabel.[25]
Dalam buku teksnya tahun 2004, David Watt menggunakan gagasan Tennent tentang sequencer untuk menjelaskan kemiripan antara break bertingkat dan pernyataan return. Watt mencatat bahwa kelas sequencer yang dikenal sebagai escape sequencer, yang didefinisikan sebagai "sequencer yang menghentikan eksekusi perintah atau prosedur yang secara tekstual membungkusnya", mencakup break dari perulangan (termasuk break bertingkat) dan pernyataan return. Namun, sebagaimana umumnya diimplementasikan, sequencer return juga dapat membawa nilai (return), sedangkan sequencer break sebagaimana diimplementasikan dalam bahasa kontemporer biasanya tidak dapat melakukannya.[27]
Pengujian di tengah
Struktur berikut diusulkan oleh Dahl pada 1972:[28]
loop loop
xxx1 read(char);
while test; while not atEndOfFile;
xxx2 write(char);
repeat; repeat;
Konstruksi ini dapat dipandang sebagai perulangan do dengan pemeriksaan while di tengah, yang memungkinkan logika loop-and-a-half yang jelas. Selain itu, dengan menghilangkan komponen tertentu, satu konstruksi ini dapat menggantikan beberapa konstruksi dalam sebagian besar bahasa pemrograman. Jika xxx1 dihilangkan, kita mendapatkan perulangan dengan pengujian di bagian atas (perulangan while tradisional). Jika xxx2 dihilangkan, kita mendapatkan perulangan dengan pengujian di bagian bawah, setara dengan perulangan do while dalam banyak bahasa. Jika while dihilangkan, kita mendapatkan perulangan tak terbatas. Konstruksi ini juga memungkinkan polaritas kondisi tetap sama meskipun berada di tengah, tidak seperti keluar lebih awal yang mengharuskan polaritas dibalik (menambahkan not),[12] sehingga berfungsi sebagai until alih-alih while.
Struktur ini tidak didukung secara luas; sebagian besar bahasa menggunakan if ... break untuk keluar secara bersyarat lebih awal.
Struktur ini didukung oleh beberapa bahasa, seperti Forth, dengan sintaks BEGIN ... WHILE ... REPEAT,[29] dan bahasa shell script Bourne shell (sh) dan bash, dengan sintaks while ... do ... done atau until ... do ... done, seperti:[30][31]
while statement-1 statement-2 ... condition do statement-a statement-b ... done
Sintaks shell tersebut bekerja karena perulangan while (atau until) menerima daftar perintah sebagai kondisi,[32] secara formal:
while'test-commands; doconsequent-commands; done
Nilai (status keluar) dari daftar test-commands adalah nilai dari perintah terakhir, dan perintah-perintah tersebut dapat dipisahkan oleh baris baru, sehingga menghasilkan bentuk idiomatik di atas.
Konstruksi serupa dimungkinkan dalam C dan C++ dengan operator koma, serta bahasa lain dengan konstruksi serupa, yang memungkinkan daftar pernyataan dimasukkan ke dalam kondisi while:
while(statement_1,statement_2,condition){ statement_a; statement_b; }
Meskipun sah, penggunaan ini tidak umum dan terutama digunakan, jika memang digunakan, hanya untuk kasus pendek yang melakukan modifikasi lalu pengujian, seperti:[33]
while(read_string(s),strlen(s)>0){ // ... }
Varian dan invarian perulangan
Varian perulangan dan invarian perulangan digunakan untuk menyatakan kebenaran perulangan.[34]
Dalam praktiknya, varian perulangan adalah ekspresi bilangan bulat yang memiliki nilai awal non-negatif. Nilai varian harus berkurang pada setiap iterasi perulangan, tetapi tidak boleh menjadi negatif selama eksekusi perulangan yang benar. Varian perulangan digunakan untuk menjamin bahwa perulangan akan berhenti.
Invarian perulangan adalah pernyataan yang harus benar sebelum iterasi pertama dan tetap benar setelah setiap iterasi. Hal ini menyiratkan bahwa ketika suatu perulangan berhenti dengan benar, baik kondisi keluar maupun invarian perulangan terpenuhi. Invarian perulangan digunakan untuk memantau sifat-sifat tertentu dari suatu perulangan selama iterasi berturut-turut.
Beberapa bahasa pemrograman, seperti Eiffel, memiliki dukungan bawaan untuk varian dan invarian perulangan. Dalam bahasa lain, dukungan tersedia sebagai tambahan, seperti spesifikasi Java Modeling Language untuk pernyataan perulangan dalam Java.
Subbahasa perulangan
Beberapa dialek Lisp menyediakan subbahasa yang luas untuk mendeskripsikan perulangan. Contoh awal dapat ditemukan dalam Conversional Lisp dari Interlisp. Common Lisp[35] menyediakan makro Loop yang mengimplementasikan subbahasa semacam itu.
Tabel referensi silang sistem perulangan
| Bahasa pemrograman | Bersyarat | Perulangan | Keluar awal | Kelanjutan perulangan | Ulangi kembali | Coba lagi | Fasilitas kebenaran | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Awal | Tengah | Akhir | Numerik | Koleksi | Umum | Tak terbatas [1] | Varian | Invarian | |||||
| Ada | Ya | Ya | Ya | Ya | arrays | Tidak | Ya | deep nested | Tidak | ||||
| APL | Ya | Tidak | Ya | Ya | Ya | Ya | Ya | deep nested [3] | Ya | Tidak | Tidak | ||
| C | Ya | Tidak | Ya | Tidak [2] | Tidak | Ya | Tidak | deep nested [3] | deep nested [3] | Tidak | Tidak | Tidak | Tidak |
| C++ | Ya | Tidak | Ya | Tidak [2] | Ya [9] | Ya | Tidak | deep nested [3] | deep nested [3] | Tidak | Tidak | Tidak | Tidak |
| C# | Ya | Tidak | Ya | Tidak [2] | Ya | Ya | Tidak | deep nested [3] | deep nested [3] | Tidak | Tidak | Tidak | Tidak |
| COBOL | Ya | Tidak | Ya | Ya | Tidak | Ya | Tidak | deep nested [15] | deep nested [14] | Tidak | |||
| Common Lisp | Ya | Ya | Ya | Ya | builtin only [16] | Ya | Ya | deep nested | Tidak | ||||
| D | Ya | Tidak | Ya | Ya | Ya | Ya | Ya[14] | deep nested | deep nested | Tidak | |||
| Eiffel | Ya | Tidak | Tidak | Ya [10] | Ya | Ya | Tidak | one level [10] | Tidak | Tidak | Tidak [11] | integer only [13] | Ya |
| F# | Ya | Tidak | Tidak | Ya | Ya | Tidak | Tidak | Tidak [6] | Tidak | Tidak | |||
| FORTRAN 77 | Ya | Tidak | Tidak | Ya | Tidak | Tidak | Tidak | one level | Ya | Tidak | Tidak | ||
| Fortran 90 | Ya | Tidak | Tidak | Ya | Tidak | Tidak | Ya | deep nested | deep nested | Tidak | Tidak | ||
| Fortran 95 dan versi selanjutnya | Ya | Tidak | Tidak | Ya | arrays | Tidak | Ya | deep nested | deep nested | Tidak | Tidak | ||
| Go | Ya | Tidak | Tidak | Ya | builtin only | Ya | Ya | deep nested | deep nested | Tidak | |||
| Haskell | Tidak | Tidak | Tidak | Tidak | Ya | Tidak | Ya | Tidak [6] | Tidak | Tidak | |||
| Java | Ya | Tidak | Ya | Tidak [2] | Ya | Ya | Tidak | deep nested | deep nested | Tidak | non-native [12] | non-native [12] | |
| JavaScript | Ya | Tidak | Ya | Tidak [2] | Ya | Ya | Tidak | deep nested | deep nested | Tidak | Tidak | Tidak | |
| Kotlin | Ya | Tidak | Ya | Mungkin | Ya | Tidak | Tidak | deep nested | deep nested | Tidak | Tidak | Tidak | Tidak |
| Natural | Ya | Ya | Ya | Ya | Tidak | Ya | Ya | Ya | Ya | Ya | Tidak | ||
| OCaml | Ya | Tidak | Tidak | Ya | arrays,lists | Tidak | Tidak | Tidak [6] | Tidak | Tidak | |||
| Odin | Tidak [17] | Tidak | Tidak | Tidak [5] | builtin only | Ya | Tidak [17] | deep nested | deep nested | ||||
| PHP | Ya | Tidak | Ya | Tidak [2] [5] | Ya [4] | Ya | Tidak | deep nested | deep nested | Tidak | Tidak | Tidak | Tidak |
| Perl | Ya | Tidak | Ya | Tidak [2] [5] | Ya | Ya | Tidak | deep nested | deep nested | Ya | |||
| Python | Ya | Tidak | Tidak | Tidak [5] | Ya | Tidak | Tidak | deep nested [6] | deep nested [6] | Tidak | Tidak | Tidak | Tidak |
| QB64 | Ya | Tidak | Ya | Ya | Tidak | Ya | Ya | one level per type of loop | one level per type of loop | Tidak | Tidak | Tidak | Tidak |
| Rebol | Tidak [7] | Ya | Ya | Ya | Ya | Tidak [8] | Ya | one level [6] | Tidak | Tidak | |||
| Ruby | Ya | Tidak | Ya | Ya | Ya | Tidak | Ya | deep nested [6] | deep nested [6] | Ya | Ya | ||
| Rust | Ya | Tidak | Tidak | Tidak [5] | Ya | Tidak | Ya | deep nested | deep nested | Tidak | Tidak | Tidak | Tidak |
| Standard ML | Ya | Tidak | Tidak | Tidak | arrays,lists | Tidak | Tidak | Tidak [6] | Tidak | Tidak | |||
| Swift | Ya | Tidak | Ya | Tidak | Ya | Ya | Tidak | deep nested | deep nested | Tidak | Tidak | Tidak | Tidak |
| Visual Basic .NET | Ya | Tidak | Ya | Ya | Ya | Tidak | Ya | one level per type of loop | one level per type of loop | Tidak | Tidak | Tidak | Tidak |
| PowerShell | Ya | Tidak | Ya | Tidak [2] | Ya | Ya | Tidak | Ya | Ya | Tidak | Tidak | Tidak | Tidak |
| Zig | Ya | Tidak | Tidak | Ya | builtin only | Tidak | Tidak | deep nested | deep nested | Tidak | Tidak | Tidak | Tidak |
- a
while (true)tidak dihitung sebagai perulangan tak terbatas untuk tujuan ini karena bukan merupakan struktur bahasa khusus. - abcdefgh Perulangan C
for (init; test; increment)merupakan konstruksi perulangan umum, bukan khusus untuk penghitungan, meskipun sering digunakan untuk tujuan tersebut. - abc Break bertingkat dapat dilakukan dalam APL, C, C++, dan C# melalui penggunaan label dan goto.
- a Iterasi terhadap objek ditambahkan dalam PHP 5.
- abcdef Perulangan penghitung dapat disimulasikan dengan melakukan iterasi pada daftar atau generator yang meningkat, misalnya
range()dalam Python. - abcde Break bertingkat dapat dilakukan melalui penanganan pengecualian.
- a Tidak ada konstruksi khusus karena fungsi
whiledapat digunakan untuk tujuan ini. - a Tidak ada konstruksi khusus, tetapi pengguna dapat mendefinisikan fungsi perulangan umum.
- a Standar C++11 memperkenalkan range-based for. Dalam STL, terdapat fungsi templat
std::for_eachyang dapat melakukan iterasi pada kontainer STL dan memanggil fungsi uner untuk setiap elemen.[36] Fungsionalitas ini juga dapat dibangun sebagai makro pada kontainer tersebut.[37] - a Perulangan numerik dilakukan dengan iterasi pada interval bilangan bulat; keluar lebih awal dilakukan dengan menyertakan kondisi tambahan untuk keluar.
- a Eiffel mendukung kata tercadang
retry, tetapi kata tersebut digunakan dalam penanganan pengecualian, bukan untuk kendali perulangan. - a Memerlukan Java Modeling Language (JML), yaitu bahasa spesifikasi antarmuka perilaku.
- a Mengharuskan varian perulangan berupa bilangan bulat; varian transfinit tidak didukung. Eiffel: Why loop variants are integers
- a D mendukung koleksi tak terbatas dan kemampuan untuk melakukan iterasi pada koleksi tersebut. Hal ini tidak memerlukan konstruksi khusus.
- a Break bertingkat dapat dicapai menggunakan
GO TOdan prosedur. - a Common Lisp mendahului konsep tipe koleksi generik.
- ab Perulangan
forumum dalam Odin mendukung pintasan sintaks untuk perulangan bersyarat dan perulangan tak terbatas.
Nonlokal
Banyak bahasa pemrograman, terutama yang lebih menyukai gaya pemrograman dinamis, menyediakan konstruksi untuk alur kendali nonlokal yang menyebabkan eksekusi melompat dari titik eksekusi saat ini ke titik yang telah dideklarasikan sebelumnya. Contoh penting di antaranya adalah sebagai berikut.
Penanganan kondisi
Kompiler Fortran paling awal mendukung pernyataan untuk menangani kondisi luar biasa, termasuk IF ACCUMULATOR OVERFLOW, IF QUOTIENT OVERFLOW, dan IF DIVIDE CHECK. Demi independensi terhadap mesin, pernyataan tersebut tidak disertakan dalam FORTRAN IV dan Standar Fortran 66. Namun, sejak Fortran 2003, masalah numerik dapat diuji melalui pemanggilan fungsi dalam modul IEEE_EXCEPTIONS.
PL/I memiliki sekitar 22 kondisi standar (misalnya, ZERODIVIDE, SUBSCRIPTRANGE, ENDFILE) yang dapat dibangkitkan dan dicegat menggunakan: ON condition action; Pemrogram juga dapat mendefinisikan dan menggunakan kondisi bernama mereka sendiri.
Seperti if tidak terstruktur, hanya satu pernyataan yang dapat ditentukan sehingga dalam banyak kasus diperlukan GOTO untuk menentukan tempat alur kendali dilanjutkan.
Sayangnya, beberapa implementasi memiliki overhead yang cukup besar dalam penggunaan ruang maupun waktu (terutama SUBSCRIPTRANGE), sehingga banyak pemrogram berusaha menghindari penggunaan kondisi.
Contoh sintaks yang umum:
ON condition GOTO label
Penanganan pengecualian
Banyak bahasa modern secara bawaan mendukung penanganan pengecualian. Umumnya, alur kendali pengecualian dimulai ketika sebuah objek pengecualian dilemparkan (disebut juga dibangkitkan). Kendali kemudian diteruskan ke penangan pengecualian terdalam pada call stack. Jika penangan menangani pengecualian tersebut, alur kendali kembali normal. Jika tidak, kendali bergerak keluar menuju penangan yang membungkusnya hingga ada yang menangani pengecualian atau program mencapai lingkup terluar dan berhenti. Ketika kendali bergerak menuju penangan yang semakin luar, aspek-aspek yang biasanya terjadi, seperti mengeluarkan elemen dari call stack, ditangani secara otomatis.
Kode C++ berikut menunjukkan penanganan pengecualian terstruktur. Jika sebuah pengecualian muncul dari eksekusi doSomething() dan tipe objek pengecualian cocok dengan salah satu tipe yang ditentukan dalam klausa catch, klausa tersebut dieksekusi. Misalnya, jika pengecualian bertipe SomeException dibangkitkan oleh doSomething(), maka kendali melompat dari baris 2 ke baris 4 dan pesan "Caught SomeException" dicetak, kemudian kendali melompat ke setelah pernyataan try, yaitu baris 8. Jika pengecualian dengan tipe lain dibangkitkan, kendali melompat dari baris 2 ke baris 6. Jika tidak ada pengecualian, kendali melompat dari baris 2 ke baris 8.
try{ doSomething(); }catch(constSomeException&e) std::println("Caught SomeException: {}",e.what()); }catch(...){ std::println("Unknown error"); } doNextThing();
Banyak bahasa menggunakan kata kunci C++ (throw, try, dan catch), tetapi beberapa bahasa menggunakan kata kunci lain. Misalnya, Ada menggunakan exception untuk memperkenalkan penangan pengecualian dan when sebagai pengganti catch. AppleScript menyertakan placeholder dalam sintaksnya untuk mengekstrak informasi tentang pengecualian seperti yang ditunjukkan dalam kode AppleScript berikut.
try set myNumber to myNumber / 0 on error e number n from f to t partial result pr if ( e = "Can't divide by zero" ) then display dialog "You must not do that" end try
Dalam banyak bahasa (termasuk Object Pascal, D, Java, C#, dan Python), klausa finally di akhir pernyataan try dieksekusi pada akhir pernyataan try, baik pengecualian diteruskan dari bagian lain try maupun tidak. Kode C# berikut memastikan bahwa aliran stream ditutup.
FileStreamstream=null; try { stream=newFileStream("logfile.txt",FileMode.Create); returnProcessStuff(stream); } finally { if(stream!=null) { stream.Close(); } }
Karena pola ini umum, C# menyediakan pernyataan using untuk memastikan pembersihan. Dalam kode berikut, bahkan jika ProcessStuff() meneruskan sebuah pengecualian, objek stream dilepaskan. Pernyataan with dalam Python dan argumen blok Ruby pada File.open digunakan untuk tujuan serupa.
using(FileStreamstream=new("logfile.txt",FileMode.Create)) { returnProcessStuff(stream); }
Kontinuasi
Generator
Korutin
COMEFROM
Keluar lebih awal dari perulangan bersarang berbasis peristiwa
Zahn's construct diusulkan pada 1974,[38] dan dibahas dalam Knuth (1974). Versi yang dimodifikasi disajikan di sini.
exitwhen EventA or EventB or EventC;
xxx
exits
EventA: actionA
EventB: actionB
EventC: actionC
endexit;
exitwhen digunakan untuk menentukan peristiwa yang mungkin terjadi di dalam xxx, yang kemunculannya ditunjukkan dengan menggunakan nama peristiwa sebagai pernyataan. Ketika suatu peristiwa terjadi, tindakan yang relevan dijalankan, kemudian kendali diteruskan tepat setelah endexit. Konstruksi ini memberikan pemisahan yang sangat jelas antara menentukan bahwa suatu situasi berlaku dan tindakan yang harus dilakukan untuk situasi tersebut.
exitwhen secara konseptual mirip dengan penanganan pengecualian, dan pengecualian atau konstruksi serupa digunakan untuk tujuan ini dalam banyak bahasa.
Contoh sederhana berikut melibatkan pencarian item tertentu dalam tabel dua dimensi.
exitwhen found or missing;
for I := 1 to N do
for J := 1 to M do
if table[I,J] = target then found;
missing;
exits
found: print ("item is in table");
missing: print ("item is not in table");
endexit;
Lihat pula
- Control-flow analysis
- Control-flow diagram
- Control-flow graph
- Control table
- Cyclomatic complexity
- DRAKON
- Flowchart – bagan yang merepresentasi sebuah proses atau alur kerja
- Spaghetti code
Referensi
- ↑ Payer, Mathias; Kuznetsov, Volodymyr. "On differences between the CFI, CPS, and CPI properties". nebelwelt.net. Diakses tanggal 2016-06-01.
- ↑ "Adobe Flash Bug Discovery Leads To New Attack Mitigation Method". Dark Reading. 10 November 2015. Diakses tanggal 2016-06-01.
{{cite web}}: Pemeliharaan CS1: Tanggal diterjemahkan otomatis (link) - ↑ Endgame. "Endgame to Present at Black Hat USA 2016". www.prnewswire.com (Rilis pers). Diakses tanggal 2016-06-01.
- ↑ Knuth, Donald E. (1974). "Structured Programming with
go toStatements". Computing Surveys. 6 (4): 261–301. doi:10.1145/356635.356640. S2CID 207630080. - 1 2 3 4 Roberts, E. [1995] "Loop Exits and Structured Programming: Reopening the Debate Diarsipkan 2014-07-25 di Wayback Machine," ACM SIGCSE Bulletin, (27)1: 268–272.
- ↑ "Nested Loops in C with Examples". GeeksforGeeks (dalam bahasa American English). 2019-11-25. Diakses tanggal 2024-03-14.
- ↑ "Python Nested Loops". www.w3schools.com (dalam bahasa American English). Diakses tanggal 2024-03-14.
- ↑ Dean, Jenna (2019-11-22). "Nested Loops". The Startup (dalam bahasa Inggris). Diakses tanggal 2024-03-14.
- 1 2 "Messy Loop Conditions". WikiWikiWeb. 2014-11-03.
- 1 2 3 Knuth 1974, hlm. 278, Simple Iterations.
- ↑ Edsger W. Dijkstra, komunikasi pribadi kepada Donald Knuth pada 1974-01-03, dikutip dalam Knuth (1974, hlm. 278, Simple Iterations)
- 1 2 3 Knuth 1974, hlm. 279.
- ↑ "What is a loop and how we can use them?". Diarsipkan dari asli tanggal 2020-07-28. Diakses tanggal 2020-05-25.
- ↑ "redo - perldoc.perl.org". perldoc.perl.org. Diakses tanggal 2020-09-25.
- ↑ "control_expressions - Documentation for Ruby 2.4.0". docs.ruby-lang.org. Diakses tanggal 2020-09-25.
- ↑ "control_expressions - Documentation for Ruby 2.3.0". docs.ruby-lang.org. Diakses tanggal 2020-09-25.
- ↑ Merupakan cara umum untuk menyelesaikan masalah loop-and-a-half.
- ↑ Advanced Bash Scripting Guide: 11.3. Loop Control
- ↑ PHP Manual: "break"
- ↑ perldoc: last
- ↑ comp.lang.c FAQ list · "Question 20.20b"
- ↑ "named-loops". open-std.org. 18 September 2024.
{{cite web}}: Pemeliharaan CS1: Tanggal diterjemahkan otomatis (link) - ↑ "Information technology — Programming languages — C" (PDF). open-std.org. 4 Mei 2025.
{{cite web}}: Pemeliharaan CS1: Tanggal diterjemahkan otomatis (link) - ↑ [Python-3000] Announcing PEP 3136, Guido van Rossum
- 1 2 Kozen, Dexter (2008). "The Böhm–Jacopini Theorem is False, Propositionally". Mathematics of Program Construction (PDF). Lecture Notes in Computer Science. Vol. 5133. hlm. 177–192. doi:10.1007/978-3-540-70594-9_11. ISBN 978-3-540-70593-2.
- ↑ Kosaraju, S. Rao. "Analysis of structured programs," Proc. Fifth Annual ACM Syrup. Theory of Computing, (May 1973), 240-252; also in J. Computer and System Sciences, 9, 3 (December 1974), cited by Knuth (1974).
- ↑ David Anthony Watt; William Findlay (2004). Programming language design concepts. John Wiley & Sons. hlm. 215–221. ISBN 978-0-470-85320-7.
- ↑ Dahl & Dijkstra & Hoare, "Structured Programming" Academic Press, 1972.
- ↑ "6. Throw It For a Loop".
- ↑ "3.2.5.1 Looping Constructs", The GNU Bash Reference Manual, 2025-05-18
- ↑ "How could a language make the loop-and-a-half less error-prone?". Stack Exchange: Programming Language Design and Implementation.
- ↑ "3.2.4 Lists of Commands", The GNU Bash Reference Manual, 2025-05-18
- ↑ "What does the comma operator , do?". Stack Overflow.
- ↑ Meyer, Bertrand (1991). Eiffel: The Language. Prentice Hall. hlm. 129–131.
- ↑ "Common Lisp LOOP macro".
- ↑ for_each. Sgi.com. Retrieved on 2010-11-09.
- ↑ Chapter 1. Boost.Foreach Diarsipkan 2010-01-29 di Wayback Machine. Boost-sandbox.sourceforge.net (2009-12-19). Retrieved on 2010-11-09.
- ↑ Zahn, C. T. "A control statement for natural top-down structured programming" presented at Symposium on Programming Languages, Paris, 1974.
Pranala luar
Media terkait Control flow di Wikimedia Commons- Go To Statement Considered Harmful
- A Linguistic Contribution of GOTO-less Programming
- "Structured Programming with Go To Statements" (PDF). Diarsipkan dari asli (PDF) tanggal 2009-08-24. (2.88 MB)
- "IBM 704 Manual" (PDF). (31.4 MB)