Apakah menggunakan goto bermanfaat?

29

gotohampir secara universal putus asa. Apakah menggunakan pernyataan ini bermanfaat?

Casebash
sumber
16
xkcd.com/292
TheLQ
1
gotoadalah apa yang cpu akhirnya lakukan, tetapi tidak bekerja dengan baik dengan apa yang manusia perlu pahami dan abstrak karena tidak ada tanda pada ujung target. Bandingkan dengan Intercal COMEFROM.
2
@ ThorbjørnRavnAndersen, apa lagi yang dimaksud manusia ketika mereka berbicara tentang transisi negara dalam mesin negara? Tidak bisakah kamu melihat kesamaan? "Pergi ke keadaan tertentu ", itulah artinya dan apa pun akan menjadi komplikasi yang tidak perlu dari hal sepele seperti itu. Dan apa yang Anda maksud dengan "tidak ada tanda"? Label adalah tanda seperti itu.
SK-logic
@ SK-logic, tergantung pada seberapa jauh Anda mengizinkan goto berasal. Mesin negara tidak membutuhkan goto untuk diimplementasikan.
@ ThorbjørnRavnAndersen, tentu saja gototidak diperlukan. Ini hanyalah cara paling rasional untuk mengimplementasikannya dalam bahasa imperatif, karena ini adalah hal yang paling dekat dengan semantik transisi negara. Dan tujuannya bisa sangat jauh dari sumbernya, tidak akan menghalangi keterbacaan. Contoh favorit saya dari kode semacam itu adalah implementasi game DE Adventure dari Knuth.
SK-logic

Jawaban:

49

Ini telah dibahas beberapa kali di Stack Overflow, dan Chris Gillum merangkum kemungkinan penggunaangoto :

Keluar dari suatu fungsi dengan bersih

Seringkali dalam suatu fungsi, Anda dapat mengalokasikan sumber daya dan harus keluar di banyak tempat. Pemrogram dapat menyederhanakan kode mereka dengan menempatkan kode pembersihan sumber daya di akhir fungsi semua "titik keluar" dari fungsi akan kebagian label pembersihan. Dengan cara ini, Anda tidak perlu menulis kode pembersihan di setiap "titik keluar" dari fungsi.

Keluar dari loop bersarang

Jika Anda berada di loop bersarang dan harus keluar dari semua loop, goto bisa membuat ini jauh lebih bersih dan lebih sederhana daripada pernyataan break dan jika-cek.

Peningkatan kinerja tingkat rendah

Ini hanya valid dalam kode perf-critical, tetapi pernyataan goto mengeksekusi sangat cepat dan dapat memberi Anda dorongan ketika bergerak melalui suatu fungsi. Namun ini adalah pedang bermata dua, karena kompiler biasanya tidak dapat mengoptimalkan kode yang berisi gotos.

Saya berpendapat, seperti banyak orang lain akan berpendapat, bahwa dalam semua kasus ini, penggunaan gotodigunakan sebagai sarana untuk keluar dari sudut satu kode ke diri sendiri, dan umumnya merupakan gejala kode yang bisa dire-refored.

Komunitas
sumber
28
Masalah pertama diselesaikan dengan sangat rapi oleh finallyblok dalam bahasa modern, dan yang kedua diselesaikan dengan label breaks. Namun, jika Anda terjebak dengan C, gotocukup satu-satunya cara untuk menyelesaikan masalah ini dengan elegan.
Chinmay Kanchi
2
Poin yang sangat bagus. Saya suka bagaimana Java memungkinkan keluar dari beberapa level loop
Casebash
4
@ Cinmay - akhirnya blok hanya berlaku untuk 1) bahasa modern yang memilikinya dan b) Anda dapat mentolerir overhead (penanganan pengecualian memang memiliki overhead). Artinya, menggunakan finallyhanya valid dalam kondisi tersebut. Ada situasi yang sangat jarang namun valid di mana goto adalah cara untuk pergi.
luis.espinal
21
Oke orang ... apa bedanya antara break 3atau break myLabeldan goto myLabel. Oh itu benar hanya kata kunci. Jika Anda menggunakan break, continueatau kata kunci serupa yang Anda gunakan menggunakan goto(Jika Anda menggunakan for, while, foreach, do/loopAnda menggunakan goto bersyarat.)
Matthew Whited
4
Tentang kinerja tingkat rendah - perilaku prosesor modern mungkin sulit untuk diprediksi (pemipaan, eksekusi out-of-order) jadi mungkin dalam 99% kasus tidak layak atau bahkan mungkin lebih lambat. @MatthewWhited: Pelingkupan. Jika Anda memasukkan ruang lingkup pada titik arbitrer tidak jelas (untuk manusia) apa yang harus disebut konstruktor (masalah ada di C juga).
Maciej Piechotka
42

Konstruksi aliran kontrol level yang lebih tinggi cenderung sesuai dengan konsep dalam domain masalah. If / else adalah keputusan berdasarkan beberapa kondisi. Loop mengatakan untuk melakukan beberapa tindakan berulang kali. Bahkan pernyataan break mengatakan "kami melakukan ini berulang kali, tapi sekarang kami harus berhenti".

Pernyataan goto, di sisi lain, cenderung sesuai dengan konsep dalam program yang sedang berjalan, bukan dalam domain masalah. Dikatakan untuk melanjutkan eksekusi pada titik tertentu dalam program . Seseorang yang membaca kode harus menyimpulkan apa artinya sehubungan dengan domain masalah.

Tentu saja semua konstruksi tingkat yang lebih tinggi dapat didefinisikan dalam hal gotos dan cabang kondisional sederhana. Itu tidak berarti bahwa mereka hanya goto yang menyamar. Pikirkan mereka sebagai goto yang dibatasi - dan pembatasanlah yang membuatnya bermanfaat. Pernyataan break diimplementasikan sebagai lompatan ke ujung loop tertutup, tetapi lebih baik dianggap beroperasi pada loop secara keseluruhan.

Semua yang lain dianggap sama, kode yang strukturnya mencerminkan bahwa dari domain masalah cenderung lebih mudah dibaca dan dipelihara.

Tidak ada kasus di mana pernyataan goto mutlak diperlukan (ada teorema untuk efek itu), tetapi ada kasus di mana itu bisa menjadi solusi yang paling buruk. Kasing tersebut bervariasi dari satu bahasa ke bahasa lain, tergantung pada tingkat konstruksi apa yang didukung oleh bahasa tersebut.

Di C, misalnya, saya percaya ada tiga skenario dasar di mana goto sesuai.

  1. Keluar dari loop bersarang. Ini tidak perlu jika bahasa tersebut memiliki pernyataan istirahat berlabel.
  2. Bailing keluar dari hamparan kode (biasanya badan fungsi) jika terjadi kesalahan atau peristiwa tak terduga lainnya. Ini tidak perlu jika bahasa tersebut memiliki pengecualian.
  3. Menerapkan mesin negara hingga eksplisit. Dalam kasus ini (dan, saya pikir, hanya dalam kasus ini) goto berhubungan langsung dengan konsep dalam domain masalah, transisi dari satu keadaan ke keadaan lain yang ditentukan, di mana keadaan saat ini diwakili oleh blok kode mana yang sedang dijalankan .

Di sisi lain, mesin negara hingga eksplisit juga dapat diimplementasikan dengan pernyataan switch di dalam loop. Ini memiliki keuntungan bahwa setiap negara mulai di tempat yang sama dalam kode, yang dapat berguna untuk debugging, misalnya.

Penggunaan utama goto dalam bahasa modern yang cukup (yang mendukung jika / else dan loop) adalah untuk mensimulasikan konstruksi aliran kontrol yang hilang dari bahasa.

Keith Thompson
sumber
5
Ini sebenarnya jawaban terbaik sejauh ini - agak mengejutkan, untuk pertanyaan yang berusia satu setengah tahun. :-)
Konrad Rudolph
1
+1 ke "jawaban terbaik sejauh ini". --- "Penggunaan utama goto dalam bahasa modern yang cukup (yang mendukung jika / lain dan loop) adalah untuk mensimulasikan konstruksi aliran kontrol yang hilang dari bahasa."
Dave Dopson
Dalam mesin status pernyataan-saklar, setiap penulisan ke nilai kontrol benar-benar a goto. SSSM sering merupakan struktur yang baik untuk digunakan, karena mereka memisahkan negara SM dari konstruk eksekusi, tetapi mereka tidak benar-benar menghilangkan "gotos".
supercat
2
"Semua dianggap sama, kode yang strukturnya mencerminkan bahwa domain masalah cenderung lebih mudah dibaca dan dipelihara." Saya sudah tahu ini sepenuhnya untuk waktu yang lama tetapi tidak memiliki kata-kata untuk mengkomunikasikannya dengan tepat sedemikian rupa sehingga programmer lain dapat dan akan benar-benar mengerti. Terima kasih untuk ini.
Wildcard
"Teorema program terstruktur" menghibur saya, karena cenderung menunjukkan dengan jelas bahwa menggunakan pernyataan pemrograman terstruktur untuk meniru goto jauh lebih mudah dibaca daripada hanya menggunakan goto!
11

Tentunya itu tergantung pada bahasa pemrogramannya. Alasan utama gototelah menjadi kontroversial adalah karena efek buruknya yang muncul ketika kompiler memungkinkan Anda menggunakannya terlalu bebas. Masalah dapat timbul, misalnya, jika memungkinkan Anda menggunakan gotosedemikian rupa sehingga Anda sekarang dapat mengakses variabel yang tidak diinisialisasi, atau lebih buruk, untuk melompat ke metode lain dan mengacaukan dengan tumpukan panggilan. Seharusnya menjadi tanggung jawab kompiler untuk melarang aliran kontrol yang tidak masuk akal.

Java telah berusaha untuk "memecahkan" masalah ini dengan menolak gotosepenuhnya. Namun, Java memungkinkan Anda menggunakan returndi dalam finallyblok dan dengan demikian menyebabkan pengecualian tertelan secara tidak sengaja. Masalah yang sama masih ada: kompiler tidak melakukan tugasnya. Menghapus gotodari bahasa belum memperbaikinya.

Dalam C #, gotoseaman break, continue, try/catch/finallydan return. Itu tidak membiarkan Anda menggunakan variabel yang tidak diinisialisasi, itu tidak membiarkan Anda melompat keluar dari blok akhirnya, dll. Kompiler akan mengeluh. Ini karena itu memecahkan masalah nyata , yang seperti saya katakan aliran kontrol tidak masuk akal. gototidak secara ajaib membatalkan analisis penugasan tertentu dan pengecekan wajar lainnya.

Timwi
sumber
Maksud Anda adalah bahwa C # gototidak jahat? Jika demikian, itu adalah kasus untuk setiap bahasa modern yang digunakan secara rutin dengan sebuah gotokonstruk, tidak hanya C # ...
lvella
9

Iya nih. Ketika loop Anda bersarang dalam beberapa level, gotoadalah satu - satunya cara untuk melepaskan loop dalam secara elegan. Opsi lainnya adalah mengatur bendera dan keluar dari setiap loop jika bendera itu memenuhi syarat. Ini benar-benar jelek, dan sangat rentan kesalahan. Dalam kasus ini, gotolebih baik.

Tentu saja, breakpernyataan berlabel Java melakukan hal yang sama, tetapi tanpa memungkinkan Anda untuk melompat ke titik sembarang dalam kode, yang menyelesaikan masalah dengan rapi tanpa membiarkan hal-hal yang membuat gotokejahatan.

Chinmay Kanchi
sumber
Adakah yang mau menjelaskan tentang downvote? Ini adalah jawaban yang benar-benar valid untuk pertanyaan ...
Chinmay Kanchi
4
goto tidak pernah merupakan jawaban yang elegan. Ketika loop Anda bersarang beberapa level, masalah Anda adalah Anda gagal membuat kode untuk menghindari loop multinested. Panggilan prosedur BUKAN musuh. (Baca makalah "Lambda: The Ultimate ...".) Menggunakan goto untuk keluar dari loop bersarang beberapa level adalah meletakkan bantuan band pada beberapa fraktur terbuka: itu mungkin sederhana tetapi itu tidak tepat menjawab.
John R. Strohm
6
Dan tentu saja, tidak pernah ada kasus aneh ketika loop bersarang disebut? Menjadi seorang programmer yang baik tidak hanya tentang mengikuti aturan, tetapi juga tentang mengetahui kapan harus melanggarnya.
Chinmay Kanchi
2
@ JohnR.Strohm Never say never. Jika Anda menggunakan istilah seperti "tidak pernah" dalam pemrograman, Anda jelas tidak berurusan dengan kasing sudut, optimisasi, kendala sumber daya, dll. Dalam loop bersarang, goto memang cara paling bersih dan elegan untuk keluar dari loop. Tidak masalah seberapa banyak Anda telah refactored kode Anda.
Sujay Phadke
@ JohnR.Strohm: Fitur kedua yang paling tidak terjawab saat beralih dari VB.NET ke C #: the Doloop. Mengapa? Karena saya dapat mengubah satu loop yang membutuhkan terobosan dalam menjadi Doloop dan ketik Exit Dodan tidak ada GoTo. Loop bersarang terjadi sepanjang waktu. Melanggar tumpukan terjadi beberapa% dari waktu.
Yosua
7

Keputusasaan yang paling besar datang dari semacam "agama" yang telah diciptakan oleh Dewa Djikstra yang memaksa pada awal tahun 60an tentang kekuatannya yang membabi buta untuk:

  • lompat ke mana saja ke dalam blok kode apa pun
    • fungsi tidak dijalankan dari awal
    • loop tidak dieksekusi dari awal
    • inisialisasi variabel yang dilewati
  • melompat menjauh dari blok kode apa pun tanpa pembersihan apa pun.

Ini tidak ada hubungannya dengan gotopernyataan bahasa modern, yang keberadaannya semata-mata karena mendukung penciptaan struktur kode selain dari bahasa yang disediakan.

Khususnya, titik utama pertama di atas diizinkan dan yang kedua dibersihkan (jika Anda gotokeluar dari blok tumpukan dilepaskan dengan benar dan semua penghancur yang tepat dipanggil)

Anda dapat merujuk jawaban ini untuk mengetahui bagaimana bahkan kode yang tidak menggunakan goto dapat dibaca. Masalahnya bukan goto itu sendiri, tetapi penggunaannya yang buruk.

Saya dapat menulis seluruh program tanpa menggunakan if, hanya for. Tentu saja, itu tidak akan mudah dibaca, terlihat canggung dan tidak perlu rumit.

Tapi masalahnya bukan for. Ini aku.

Hal suka break, continue, throw, bool needed=true; while(needed) {...}, dll mencatat lebih dari masquerade goto untuk melarikan diri jauh dari pedang dari fanatik Djikstrarian, bahwa -50 tahun setelah penemuan laguages- modern yang masih ingin tawanan mereka. Mereka lupa apa yang dibicarakan Djikstra, mereka hanya ingat judul catatannya (GOTO dianggap berbahaya, dan itu bahkan bukan judulnya sendiri: itu diubah oleh editor) dan menyalahkan dan bash, bash dan menyalahkan setiap konstruksi yang memiliki 4 surat ditempatkan secara berurutan.

Ini tahun 2011: saatnya untuk memahami bahwa gototidak perlu berurusan dengan GOTOpernyataan yang Djikstra tuntut.

Emilio Garavaglia
sumber
1
"Hal-hal seperti istirahat, lanjutkan, lempar, bool needed = true; sementara (diperlukan) {...}, dll. Mencatat lebih dari sekadar menyamar goto" Saya tidak setuju dengan itu. Saya lebih suka "hal-hal seperti istirahat dll dibatasi goto", atau sesuatu seperti itu. Masalah utama dengan goto adalah biasanya terlalu kuat. Sejauh goto saat ini kurang kuat dari Dijkstra, jawaban Anda baik-baik saja dengan saya.
Muhammad Alkarouri
2
@MuhammadAlkarouri: Saya sepenuhnya setuju. Anda baru saja menemukan kata-kata yang lebih baik untuk mengekspresikan konsep saya dengan tepat. Maksud saya adalah bahwa pembatasan itu terkadang tidak dapat diterapkan dan jenis pembatasan yang Anda butuhkan tidak dalam bahasa. Maka hal yang lebih "kuat", kurang terspesialisasi, adalah apa yang membuat Anda mampu mengatasinya. Sebagai contoh, Java break ntidak tersedia di C ++, karenanya goto escape, bahkan jika escapetidak diharuskan untuk keluar dari loop n-ple.
Emilio Garavaglia
4

Goto aneh di sini atau di sana, selama itu lokal untuk suatu fungsi, jarang secara signifikan merusak keterbacaan. Seringkali manfaat dengan menarik perhatian pada fakta bahwa ada sesuatu yang tidak biasa terjadi dalam kode ini yang memerlukan penggunaan struktur kontrol yang agak tidak biasa.

Jika goto (lokal) secara signifikan merusak keterbacaan, maka itu biasanya merupakan tanda bahwa fungsi yang mengandung goto menjadi terlalu kompleks.

Goto terakhir yang saya masukkan ke dalam sepotong kode C adalah membangun sepasang loop yang saling terkait. Ini tidak sesuai dengan definisi normal penggunaan goto "dapat diterima", tetapi fungsi tersebut berakhir secara signifikan lebih kecil dan lebih jelas. Untuk menghindari kebotakan akan membutuhkan pelanggaran DRY yang sangat berantakan.

blucz
sumber
1
Jawaban untuk ini paling banyak disebutkan dalam slogan "Lay's Potato Chips": "Taruhan Anda tidak bisa makan hanya satu". Dalam contoh Anda, Anda memiliki dua loop "saling" (apa pun artinya, dan saya bertaruh itu tidak cantik), dan goto memberi Anda keluar murah. Bagaimana dengan petugas pemeliharaan, yang harus memodifikasi kode itu setelah Anda tertabrak bus? Apakah goto akan membuat hidupnya lebih mudah atau lebih sulit? Apakah kedua loop itu perlu dipikirkan kembali?
John R. Strohm
3

Saya pikir seluruh masalah ini adalah kasus menggonggong pohon yang salah.

GOTO seperti itu tampaknya tidak bermasalah bagi saya, tetapi itu lebih sering merupakan gejala dari dosa yang sebenarnya: kode spaghetti.

Jika GOTO menyebabkan persimpangan besar garis kontrol aliran maka itu buruk, titik. Jika tidak ada garis kontrol aliran, itu tidak berbahaya. Di zona abu-abu di antara kami memiliki hal-hal seperti bailout lingkaran, masih ada beberapa bahasa yang belum menambahkan konstruksi yang mencakup semua kasus abu-abu yang sah.

Satu-satunya kasus saya menemukan diri saya benar-benar menggunakannya dalam beberapa tahun adalah kasus loop di mana titik keputusan berada di tengah-tengah loop. Anda memiliki kode duplikat, bendera, atau GOTO. Saya menemukan solusi GOTO yang terbaik dari ketiganya. Tidak ada persimpangan jalur kontrol aliran di sini, tidak berbahaya.

Loren Pechtel
sumber
Kasing yang Anda singgung kadang-kadang dijuluki "loop setengah" atau "N ditambah satu setengah lingkaran" dan ini merupakan case yang terkenal untuk gotos yang melompat ke dalam loop (jika bahasa memungkinkan ini; karena kasus lain, melompat keluar dari loop di tengah, biasanya sepele tanpa goto).
Konrad Rudolph
(Sayangnya, sebagian besar bahasa melarang lompatan.)
Konrad Rudolph
@KonradRudolph: Jika Anda menerapkan "loop" dengan GOTO tidak ada struktur loop lain untuk melompat ke.
Loren Pechtel
1
Saya berpikir untuk gotoberteriak ALIRAN PENGENDALIAN DI SINI TIDAK SESUAI DENGAN POLA PEMROGRAMAN TERSTRUKTUR NORMAL . Karena aliran kontrol yang sesuai dengan pola pemrograman terstruktur lebih mudah untuk dipikirkan daripada yang tidak, orang harus berusaha menggunakan pola tersebut jika memungkinkan; jika kode cocok dengan pola seperti itu, orang tidak boleh berteriak bahwa itu tidak. Di sisi lain, dalam kasus-kasus di mana kode benar-benar tidak cocok dengan pola-pola seperti itu, berteriak tentang itu mungkin lebih baik daripada berpura-pura kode cocok ketika sebenarnya tidak.
supercat
1

Ya, goto dapat digunakan untuk memberi manfaat pada pengalaman pengembang: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

Namun, seperti halnya alat yang ampuh (pointer, multiple inheritance, dll.), Seseorang harus disiplin menggunakannya. Contoh yang disediakan dalam tautan menggunakan PHP, yang membatasi penggunaan konstruksi goto ke fungsi / metode yang sama dan menonaktifkan kemampuan untuk melompat ke blok kontrol baru (misalnya, loop, pernyataan switch, dll.)

AdamJonR
sumber
1

Tergantung pada bahasanya. Ini masih banyak digunakan dalam pemrograman Cobol, misalnya. Saya juga bekerja pada perangkat Barionet 50, yang bahasa pemrograman firmware-nya adalah dialek BASIC awal yang tentu saja mengharuskan Anda untuk menggunakan Goto.

pengguna16764
sumber
0

Saya akan mengatakan tidak. Jika Anda merasa perlu menggunakan GOTO, saya berani bertaruh bahwa ada kebutuhan untuk mendesain ulang kode.

Walter
sumber
3
Mungkin, tetapi Anda belum memberikan alasan apa pun
Casebash
Dijkstra memberikan alasan, secara rinci, beberapa dekade yang lalu.
John R. Strohm
2
Hanya Dogma. Tidak ada resons Catatan: Djikstra BUKANLAH LEBIH LANJUT RESON: itu merujuk pada pernyataan BASIC atau FORTRAN GOTO pada awal 60-an. Mereka tidak ada hubungannya dengan yang benar-benar anemia (dibandingkan dengan kekuatan mereka) yang kena dari hari ini.
Emilio Garavaglia
0

gotomungkin berguna saat memindahkan kode assembler lawas ke C. Pada contoh pertama, konversi instruksi-demi-instruksi ke C, menggunakan gotosebagai pengganti untuk branchinstruksi assembler , dapat memungkinkan porting yang sangat cepat.

Graham Borland
sumber
-1

Saya berpendapat tidak. Mereka harus selalu diganti dengan alat yang lebih spesifik untuk masalah goto sedang digunakan untuk menyelesaikan (kecuali itu tidak tersedia dalam bahasa Anda). Sebagai contoh, break statemen dan pengecualian memecahkan masalah yang sebelumnya diselesaikan dengan kebohongan loop melarikan diri dan penanganan kesalahan.

Fishtoaster
sumber
Saya berpendapat bahwa ketika bahasa memiliki kedua fitur ini, gotobiasanya tidak ada bahasa tersebut.
Chinmay Kanchi
Tetapi apakah itu karena mereka tidak membutuhkannya, atau karena orang berpikir mereka tidak membutuhkannya?
Michael K
Pandangan Anda fanatik. Ada banyak kasus ketika gotohal yang paling dekat dengan semantik domain yang sangat bermasalah, yang lain akan menjadi hack kotor.
SK-logic
@ SK-logic: Saya tidak berpikir kata "fanatik" berarti apa yang Anda pikirkan artinya.
Keith Thompson
1
@Keith, "yang secara intoleran mengabdikan diri pada pendapat dan prasangka sendiri" - itulah yang saya amati secara konsisten di sini, dengan banyak hal yang ditutup-tutupi. "Harus selalu diganti" adalah kata-kata fanatik, setidaknya. Tidak ada yang mendekati pendapat yang benar dan masuk akal, tetapi hanya kefanatikan murni. Ini "selalu" tidak meninggalkan ruang untuk opini alternatif, lihat?
SK-logic