Goto kullanmak her zaman değerli midir?


29

gotoneredeyse evrensel olarak cesareti kırılmıştır. Bu ifadeyi kullanmak hiç değerli mi?



1
gotonihayetinde cpu ne yapar, ancak hedef ucunda hiçbir iz olmadığı için insanların anlama ve soyutlama ihtiyacı olanlarla iyi çalışmaz. Intercal ile karşılaştırın COMEFROM.

2
@ ThorbjørnRavnAndersen, bir devlet makinesinde devlet geçişleri hakkında konuşurken insanlar ne anlama geliyor ? Bir benzerlik göremiyor musun? “Belirli bir duruma git ”, bunun anlamı ve başka bir şey böyle önemsiz bir şeyin gereksiz bir komplikasyonundan başka bir şey olmayacaktı. Ve "işaretsiz" ile ne demek istiyorsun? Etiket böyle bir işarettir.
SK-mantık

@ SK-mantığı, gotoların gelmesine ne kadar izin vereceğinize bağlıdır. Devlet makineleri uygulamak için goto gerektirmez.

@ ThorbjørnRavnAndersen, elbette gotogerekli değildir. Devlet geçişinin anlambilimine en yakın şey olduğundan, bunları zorunlu dillerde uygulamanın en rasyonel yolu budur. Hedefi kaynağından oldukça uzak olabilir, okunabilirliği engellemez. Böyle bir kodun en sevdiğim örneği DE Knuth'un Adventure oyunu uygulaması.
SK-mantık

Yanıtlar:


49

Bu, Stack Overflow'da birkaç kez tartışıldı ve Chris Gillum , olası kullanımlarını özetledigoto :

Bir fonksiyondan temiz bir şekilde çıkma

Genellikle bir işlevde, kaynakları tahsis edebilir ve birden fazla yerden çıkmanız gerekebilir. Programcılar kaynak temizleme kodunu fonksiyonun sonuna yerleştirerek kodlarını basitleştirebilirler, fonksiyonun tüm “çıkış noktaları” temizleme etiketine girer. Bu sayede, fonksiyonun her "çıkış noktasına" temizleme kodu yazmanız gerekmez.

Yuvalanmış döngülerden çıkma

Yuvalanmış bir döngü içindeyseniz ve tüm döngülerden ayrılmanız gerekiyorsa, bir goto break ifadelerinden ve if-check'lerden çok daha temiz ve basit hale getirebilir.

Düşük seviye performans iyileştirmeleri

Bu, yalnızca kritik kodlarda geçerlidir, ancak goto ifadeleri çok hızlı bir şekilde çalışır ve bir işlev içinde ilerlerken size bir destek verebilir. Ancak bu, iki ucu keskin bir kılıçtır, çünkü bir derleyici genellikle goto içeren kodu optimize edemez.

Diğerlerinin de iddia ettiği gibi, tüm bu durumlarda, kullanımının gotobir köşeden çıkmak için kendini bir araç haline getirmenin bir aracı olarak kullanıldığını ve genellikle yeniden düzeltilebilecek bir kod belirtisi olduğunu savunuyorum.


28
İlk sorun, finallymodern dillerdeki bloklarla çok düzgün bir şekilde çözülür ve ikincisi ise breaks etiketli olarak çözülür . Bununla birlikte, C ile sıkıştınızsa, gotobu sorunları zarif bir şekilde çözmenin tek yolu budur.
Chinmay Kanchi

2
Çok iyi noktalar. Java'nın çoklu döngüler seviyelerinin dışına çıkmasına izin vermesini seviyorum
Casebash

4
@Chinmay -. Sonunda blokları sadece onlara sahip ve b) bir yükü var havai (durum işleme tahammül 1) modern diller için geçerli) İşte kullanılarak olduğu finallybu koşullar altında geçerlidir. Bir goto'nun gitmesinin yolu olduğu çok nadir, ancak geçerli durumlar var.
luis.espinal,

21
Tamam millet ... break 3ya da break myLabelve arasındaki farkın ne olduğunu goto myLabel? Ah bu sadece anahtar kelime. Eğer kullanıyorsanız break, continueya da benzer bir anahtar kelimeyi kullanıyorsanız, goto(Eğer for, while, foreach, do/loopkullanıyorsanız şartlı bir goto kullanıyorsunuzdur.)
Matthew Whited

4
Düşük seviye performans hakkında - modern işlemcinin davranışını tahmin etmek zor olabilir (boru hattı, sıra dışı çalıştırma), bu yüzden muhtemelen vakaların% 99'unda buna değmez hatta daha yavaş olabilir. @MatthewWhited: Kapsam belirleme. Kapsamı isteğe bağlı bir noktaya girerseniz, hangi yapıcıların adlandırılması gerektiği (insan için de) açık değildir (sorun C de var).
Maciej Piechotka

42

Daha yüksek seviye kontrol akış yapıları, problem alanındaki kavramlara karşılık gelme eğilimindedir. Bir if / else, bazı koşullara dayanan bir karardır. Bir döngü tekrar tekrar bazı eylem gerçekleştirmek için diyor. Bir mola bile olsa, "bunu tekrar tekrar yapıyorduk ama şimdi durmamız gerekiyor" diyor.

Öte yandan, bir goto ifadesi, sorun alanındaki değil, çalışan programdaki bir konsepte karşılık gelme eğilimindedir. Programda belirtilen noktada yürütmeye devam edeceğini söylüyor . Kodu okuyan birinin , problem alanına göre ne anlama geldiğini çıkarması gerekir.

Tabii ki tüm üst düzey yapılar, gotos ve basit koşullu dallar olarak tanımlanabilir. Bu, sadece kılık değiştirdikleri anlamına gelmez. Onları sınırlı gotos olarak düşünün - ve bu onları faydalı kılan kısıtlamalardır. Bir break ifadesi, kapatma döngüsünün sonuna bir atlama olarak uygulanır, ancak döngü üzerinde bir bütün olarak çalışması daha iyi düşünülür.

Diğer her şey eşittir, yapısı problem alanının yapısını yansıtan kodun okunması ve bakımı daha kolay olma eğilimindedir.

Bir goto ifadesinin kesinlikle gerekli olduğu durumlar yoktur ( bu etkiye yönelik bir teorem vardır), fakat bunun en kötü çözüm olabileceği durumlar vardır. Bu durumlar, dilin hangi seviyeyi desteklediğine bağlı olarak dilden dile değişir.

Örneğin C'de, bir goto'nun uygun olduğu üç temel senaryo olduğuna inanıyorum.

  1. Yuvalanmış bir döngüden kopma. Dilin etiketli bir break ifadesi olsaydı bu gereksiz olurdu.
  2. Bir hata veya beklenmeyen bir olay durumunda bir kod genişliğinden (tipik olarak bir işlev gövdesi) kurtulma. Dil istisnalar olsaydı, bu gereksiz olurdu.
  3. Açık bir sonlu durumlu makinenin uygulanması. Bu durumda (ve sanırım, sadece bu durumda), bir goto doğrudan mevcut durumdaki hangi kod bloğunun yürütüldüğü mevcut durumun temsil edildiği bir durumdan belirli bir duruma geçerek problem alanındaki bir konsepte tekabül eder .

Öte yandan, açık bir sonlu durumlu makine, bir döngü içindeki bir switch ifadesi ile de uygulanabilir. Bunun, her durumun kodda, örneğin hata ayıklama için yararlı olabilecek aynı yerden başlaması avantajı vardır.

Bir goto'nun oldukça modern bir dilde (eğer / başkalarını ve döngüleri destekleyen) ana kullanımı, dilde eksik olan bir kontrol akışı yapısını simüle etmektir.


5
Bu aslında şu ana kadarki en iyi cevap - bir buçuk yaşında olan bir soru için oldukça şaşırtıcı. :-)
Konrad Rudolph 16

1
+1 ila "şu ana kadarki en iyi cevap". --- "Bir goto'nun oldukça modern bir dilde (eğer / başkaları ve döngüleri destekleyen) ana kullanımı, dilde eksik olan bir kontrol akışı yapısını simüle etmektir."
Dave Dopson

Anahtar-ifade durum makinesinde, kontrol değerine her yazma gerçekten bir goto. SSSM'ler genellikle kullanımı iyi yapılardır, çünkü SM durumunu yürütme yapısından ayırırlar, ancak “goto'ları” gerçekten ortadan kaldırmazlar.
supercat

2
"Diğer her şey eşit olduğunda, yapısı sorun alanının yapısını yansıtan kodun okunması ve bakımı daha kolay olma eğilimindedir." Bunu çok uzun zamandır biliyordum ama diğer programcıların anlayabilecekleri ve anlayabilecekleri bir biçimde tam anlamıyla iletişim kurma sözcüklerinden yoksundum. Bunun için teşekkür ederim.
Joker

“Yapısal program teoremi” beni şaşırtıyor, çünkü açıkça bir gotoyu taklit etmek için yapılandırılmış programlama ifadeleri kullanmanın sadece bir goto kullanmaktan daha az okunabilir olduğunu açıkça ortaya koyma eğiliminde!

11

Elbette bu programlama diline bağlı. Asıl neden gototartışmalı olmuştur, derleyici onu çok liberal bir şekilde kullanmanıza izin verdiğinde ortaya çıkan kötü etkilerinden kaynaklanmaktadır. Örneğin, gotobaşka bir yönteme atlamak ve çağrı yığınıyla uğraşmak için şimdi başlatılmamış bir değişkene erişebilecek veya daha kötüsü kullanmanıza izin verecek şekilde kullanabiliyorsanız, sorunlar ortaya çıkabilir . Saçma sapan kontrol akışına izin vermemek derleyicinin sorumluluğunda olmalıdır.

Java, bu sorunu gototamamen reddederek bu sorunu “çözmeye” çalıştı . Bununla birlikte, Java returnbir finallyblok içinde kullanmanıza izin verir ve bu nedenle de yanlışlıkla yutulması için bir istisna oluşturur. Aynı sorun hala var: derleyici işini yapmıyor. Dilden kaldırmak gotoonu çözmedi.

C # gotogüvenli gibidir break, continue, try/catch/finallyve return. Başlatılmamış değişkenleri kullanmanıza izin vermiyor, sonunda bir bloktan atlamanıza vb. İzin vermiyor. Derleyici şikayet edecek. Bunun sebebi , saçma sapan kontrol akışında söylediğim gibi gerçek sorunu çözmesidir. gotokesin atama analizini ve diğer makul derleyici kontrollerini sihirli bir şekilde iptal etmez.


Demek istediğin, C # 'nın gotoşeytan olmadığı mı? Öyleyse, rutin olarak kullanılan her modern dil için bir gotoyapı içeren durum budur, yalnızca C # ...
lvella

9

Evet. Döngüleriniz birkaç seviye derinlikte iç içe gotoolduğunda, bir iç döngüden zarif bir şekilde ayrılmanın tek yolu budur. Diğer seçenek, bir bayrak koyar ve eğer bu bayrak bir koşulu yerine getirirse her döngüden kopar. Bu gerçekten çirkin ve oldukça hata eğilimli. Bu gibi durumlarda, gotosadece daha iyidir.

Tabii ki, Java'nın etiketli breakifadesi aynı şeyi yapar, ancak kodda rastgele bir noktaya atlamanıza izin vermeden, bu, gotokötülük yapan şeylere izin vermeden sorunu düzgünce çözer .


Olumsuz oyu açıklamak isteyen var mı? Bu soruya tam olarak geçerli bir cevaptı ...
Chinmay Kanchi

4
Goto asla zarif bir cevap değildir. Döngüleriniz birkaç kat derinlere yuvalanmışsa, sorun çok kodlu döngülerden kaçınmak için kodunuzu oluşturmamanızdır. Prosedür çağrıları düşman değildir. ("Lambda: The Ultimate ..." makalelerini okuyun.) Birkaç seviye derinlemesine iç içe geçmiş halkalardan kopmak için bir goto kullanmak çoklu açık kırılmaya yara bandı koymak: basit olabilir ama doğru değil Cevap.
John R. Strohm

6
Ve tabii ki, derinlemesine iç içe döngüler çağrıldığında asla garip bir durum olmaz mı? İyi bir programcı olmak sadece kurallara uymakla kalmaz, aynı zamanda ne zaman kırılacağını bilmekle de ilgilidir.
Chinmay Kanchi,

2
@ JohnR.Strohm Asla asla deme. Programlamada "asla" gibi terimler kullanırsanız, açıkça köşe senaryoları, optimizasyon, kaynak kısıtlamaları vb. İle ilgilenmediniz. Derinlemesine iç içe geçmiş döngülerde, goto gerçekten döngülerden çıkmak için en temiz ve en zarif yoldur. Kodunuzu ne kadar yeniden etkilediğiniz önemli değil.
Sujay Phadke

@ JohnR.Strohm: VB.NET'ten C # 'ya geçişte en çok kullanılan ikinci özellik: Dodöngü. Niye ya? Çünkü derin bir mola gerektiren bir Dodöngüyü bir döngü ve tür haline getirebilirim Exit Dove hayır GoTo. İç içe döngüler her zaman olur. Yığınları kırmak zamanın bir kısmı olur.
Joshua

7

Bu caydırıcılığın çoğu, 60'lı yılların başlarında, ayrım gözetmeyen gücüyle ilgili olarak zorlayan Tanrı Djikstra'nın yarattığı bir tür "din" den geliyor:

  • herhangi bir kod bloğuna herhangi bir yere atlamak
    • işlev başlangıçtan itibaren çalıştırılmadı
    • döngüler baştan başlamaz
    • atlanan değişken başlatma
  • Herhangi bir kodlama bloğundan uzaklaşmadan, herhangi bir olası temizlik işlemi yapılmadan

Bunun goto, sadece dilin sağladığı dilden başka kod yapılarının oluşturulmasını desteklemesi nedeniyle var olan modern dillerin ifadesi ile ilgisi yoktur .

Özellikle, yukarıdaki ilk ana noktaya artık izin verilir ve ikincisi temizlenir ( gotobir bloktan çıkarsanız yığın uygun şekilde çözülür ve tüm uygun yıkıcılar çağırılır)

Goto kullanmıyorsanız bile kodun nasıl okunamadığı hakkında bir fikir edinmek için bu cevaba başvurabilirsiniz . Sorun kendiliğinden değil, kötü kullanımından kaynaklanıyor.

Ben kullanmadan bütün bir program yazabilirsiniz ifsadece for. Tabii ki, iyi okunaklı olmayacak, sakar ve gereksiz yere karmaşık bir görünüm.

Ancak sorun değil for. Benim.

Yapılacaklar sever break, continue, throw, bool needed=true; while(needed) {...}, vb birden belirterek vardır Maskeli goto -50 yaş Modern laguages- icadından sonra hala esirlerini istediğiniz, Djikstrarian fanatik Scimitars uzak kaçmaya. Djikstra'nın ne hakkında konuştuğunu unuttular, yalnızca notunun başlığını hatırladılar (GOTO zararlı olduğunu düşünüyordu ve onw unvanı bile değildi: editör tarafından değiştirildi) ve bunlara sahip olan her yapıyı suçlayıp bash, bash ve suçluyorlar. mektup sırayla yerleştirilir.

2011: Djikstra'nın zorlayıcı gotoolduğu GOTOifadesiyle uğraşmadığını anlamanın zamanı geldi.


1
“Kırılma, devam etme, fırlatma, bool gerekli gibi şeyler = doğru; (gerekli) {...} vb. Artık maskeli balodan daha fazla bir şey ifade etmiyorken” buna katılmıyorum. "Mola gibi şeyler sınırlı kalsa da" ya da onun gibi bir şey tercih ederdim . Gotoyla ilgili asıl sorun, genellikle çok güçlü olmasıdır. Mevcut durumun Dijkstra'nınkilerden daha az güçlü olduğu ölçüde cevabınız bana iyi geliyor.
Muhammad Alkarouri,

2
@MuhammadAlkarouri: Kesinlikle katılıyorum. Tam olarak benim konseptimi ifade etmek için daha iyi bir ifade buldun. Demek istediğim, bu kısıtlamaların bazen uygulanamayacağı ve ihtiyaç duyduğunuz kısıtlamaların dilde olmamasıdır. O zaman, daha az uzmanlaşmış, daha "güçlü" bir şey, sizi geçici olarak çözüme kavuşturan şeydir. Örneğin, Java break nC ++ 'da mevcut değildir, bu nedenle goto escape, escapen-ple döngüsünden çıkması gerekmese bile .
Emilio Garavaglia

4

Burada ya da oradaki gariplik, bir fonksiyonun yerel olduğu sürece, nadiren okunabilirliği önemli ölçüde zedelemektedir. Genellikle, bu kodda alışılmadık bir kontrol yapısının kullanılmasını gerektiren olağandışı bir şeyin olduğuna dikkat çekerek fayda sağlar.

Eğer (yerel) goto'lar okunabilirliğe önemli ölçüde zarar veriyorsa, bu genellikle gotoyu içeren fonksiyonun çok karmaşıklaştığının bir işaretidir.

Bir C koduna koyduğum son geçiş, bir çift birbirine geçen ilmekler oluşturmaktı. Normal "kabul edilebilir" kullanım tanımına uymuyor, ancak sonuç olarak işlev çok daha küçük ve netleşti. Goto önlemek için özellikle dağınık bir DRY ihlali gerekirdi.


1
Bunun cevabı en eski "Lay's Patates Cipsi" sloganında şöyle yazılmıştı: "Bahis sadece bir tane yiyemezsin". Örneğinizde, iki "birbirine kenetlenme" (ne demekse ve ben bahse girerim güzel değil) döngüler var ve goto size ucuz bir teklif verdi. Peki ya otobüse çarptıktan sonra bu kodu değiştirmek zorunda olan bakım elemanı? Goto hayatını kolaylaştıracak mı yoksa zorlaştıracak mı? Bu iki döngünün yeniden düşünülmesi gerekiyor mu?
John R. Strohm

3

Bence bu mesele yanlış ağacın havlanmasıyla ilgili bir durum.

GOTO benim için sorunlu görünmüyor, ama daha ziyade gerçek bir günah belirtisi: spagetti kodu.

GOTO, akış kontrol hatlarının ana geçişine neden olursa, o zaman kötüdür. Akış kontrol çizgilerini geçmezse zararsızdır. Aradaki gri bölgede döngü kurtarmaları gibi şeylere sahibiz, hala tüm yasal gri kasaları kapsayan yapılar eklememiş bazı diller var.

Kendimi yıllarca kullandığımı tespit ettiğim tek vaka, karar noktasının döngünün ortasında olduğu döngünün durumu. Yinelenen kod, bayrak veya GOTO ile bıraktınız. GOTO çözümünü üçün en iyisi buluyorum. Burada hiçbir akış kontrol çizgisi geçilmez, zararsızdır.


Hoşunuza giden dava bazen "döngü bir buçuk" veya "N artı bir yarı döngü" olarak adlandırılır ve ' gotobir döngünün içine atlayan ünlü bir kullanım durumudur (eğer dil buna izin veriyorsa; Ortadaki ilmek dışına, genellikle olmadan önemsiz goto).
Konrad Rudolph

(Ne yazık ki, çoğu dil bir döngüye atlamayı yasaklar.)
Konrad Rudolph

@KonradRudolph: "loop" u GOTO ile uygularsanız, içine atlamak için başka bir döngü yapısı yoktur.
Loren Pechtel

1
Aklıma gotobağırarak olarak BURADA KONTROL AKIŞI etmez FIT NORMAL STRUCTURED-PROGRAMLAMA DESENLERİNİN . Yapılandırılmış programlama kalıplarına uyan kontrol akışlarının neden olmadıklarından daha kolay anlaşılması gerektiğinden, mümkün olduğunda bu kalıpları kullanmaya çalışılmalıdır; Eğer kod bu tür kalıplara uyuyorsa, kimse buna uymamasını söylememelidir. Öte yandan, kodun gerçekten bu tarzlara uymadığı durumlarda, bunun hakkında bağırmak, kodun gerçekten uymadığı zamanki gibi davranmaktan daha iyi olabilir.
Supercat

1

Evet, goto geliştiricinin deneyiminden yararlanmak için kullanılabilir: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

Bununla birlikte, herhangi bir güçlü araçta (işaretçiler, çoklu kalıtım vb.) Olduğu gibi, birinin de disipline edilmesi gerekir. Bağlantıda verilen örnek, goto yapısının kullanımını aynı işleve / yönteme kısıtlayan ve yeni bir kontrol bloğuna (örneğin, loop, switch deyimi, vb.) Atlamayı engelleyen PHP kullanır.


1

Dile bağlıdır. Örneğin, Cobol programlamada hala yaygın olarak kullanılmaktadır. Ayrıca, firmware programlama dili, tabii ki Goto'yu kullanmanızı gerektiren bir BASIC lehçesi olan bir Barionet 50 cihazında da çalıştım.


0

Hayır derdim. GOTO kullanımına ihtiyaç duyuyorsanız, kodun yeniden tasarlanması gereği olduğuna bahse girerim.


3
Belki, ama herhangi bir sebep
vermediniz

Dijkstra, akıl yürütmeyi onlarca yıl önce ayrıntılı olarak verdi.
John R. Strohm

2
Sadece Dogma. Cevap yok. Not: Djikstra GEÇERLİ BİR RESON DAHA FAZLA DEĞİL: 60'ların başlarındaki BASIC veya FORTRAN GOTO ifadesine atıfta bulundu. Günümüzdeki gerçek anemiklerle (bunların gücüyle karşılaştırıldığında) alakası yok.
Emilio Garavaglia

0

gotoEski montajcı kodunu C'ye taşırken faydalı olabilir. İlk örnekte, gotomontajcının branchtalimatının yerine geçen C'ye talimat talimatı dönüşümü çok hızlı bir şekilde yerleştirmeyi sağlayabilir.


-1

Hayır diyebilirim. Her zaman goto'nun çözmek için kullandığı soruna daha özel bir araçla değiştirilmelidir (sizin dilinizde mevcut değilse). Örneğin, break cümleleri ve istisnalar, daha önce döngüden kaçış ve hata yönetimi problemlerini çözer.


Dillerin her ikisi de bu özelliklere sahipken goto, genellikle bu dillerden yoksun olduğunu iddia ediyorum .
Chinmay Kanchi

Fakat bu onlara ihtiyaç duymadıkları için mi, yoksa insanlar ihtiyaç duymadıklarını düşünüyor mu?
Michael K,

Görüşlerin yüceltilir. Birçok durumlar vardır gotoçok sorun alanı semantik en yakın şey, başka bir şey kirli kesmek olacaktır.
SK-mantık

@ SK-mantık: "Bigot" kelimesinin ne anlama geldiğini anlamadığını düşünüyorum.
Keith Thompson,

1
@Keith, “hoşgörüsüzce kendi görüş ve önyargılarına adanmış” - bu sürekli göz kamaştırıcı gözü kapalı lotla burada sürekli gözlemlediğim şey bu. "Her zaman değiştirilmeli" en azından fanatiklerin sözleridir. Düzgün, sağlam bir görüşe yakın hiçbir şey yok, ama sadece saf bir bağlanma. Bu "her zaman" alternatif bir görüşe yer bırakmaz, bkz.
SK-mantık
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.