Denemek için neden parantez gerekli?


38

Çeşitli dillerde (en azından Java, aynı zamanda C #? Düşün) gibi şeyler yapabilirsiniz

if( condition )
    singleStatement;

while( condition )
    singleStatement;

for( var; condition; increment )
    singleStatement;

Dolayısıyla, yalnızca bir ifadem olduğunda, yeni bir kapsam eklemem gerekmez { }. Neden bunu try-catch ile yapamıyorum?

try
    singleStatement;
catch(Exception e)
    singleStatement;

Her zaman yeni bir kapsamın olmasını gerektiren try-catch ile ilgili özel bir şey var mı? Ve eğer öyleyse, derleyici bunu düzeltemez mi?


3
Sirke-toplama burada: Kesinlikle için konuşma forparçaları gibi bir ad olmalıdır initial, conditionve stepsıra initialihtiyacı bir değişken tanımlamak değil ve stepbir artım olması gerekmez.
Joachim Sauer

4
Bir yan nota olarak D, tek bir ifadenin etrafındaki parantez gerektirmez, catch blokları deneyin
cırcır ucube 14:

13
Bence asıl soru, diğer taraftan yuvarlak: neden bazı yapılar "çıplak" ifadelere izin veriyor? Parantezler her yerde tutarlılık için zorunlu olmalıdır.
--Zeiv

3
@ UnneceZeiv - izleyen ifşeyin daima tek bir deyim olduğunu düşünüyorsanız ve parantez içine alınmış çoklu deyimlerin tek bir deyim içerdiğini düşünüyorsanız tutarsız değildir . Ama ben her zaman her zaman diş tellerini
takanlardan biriyim

1
Parantezleri de yazma eğilimindeyim, ama gibi throwve doğrudan çıkış noktalarım olduğunda bunları yazmak zorunda returnkalmamayı seviyorum ve @detly'nin dediği gibi, eğer parantezi tek bir ifade grubu olarak görürseniz, bulamıyorum ya tutarsız. İnsanların bahsettiği bu "kodlama hataları" nın ne olduğunu asla anlamadım. İnsanların yaptıklarına dikkat etmeye başlaması, doğru niyet kullanmaları ve birim testleri yapmaları gerekir: P bu konuda hiçbir zaman bir sorun yaşamadı ...
Svish

Yanıtlar:


23

IMO, daha önce C ++ 'da bulunduğundan Java ve C #' ya dahil edildiler. Asıl soru, öyleyse, neden C ++ bu şekilde? C ++ 'nın Tasarım ve Evrimine Göre (§16.3):

tryAnahtar kelime tamamen gereksiz ve böylece olan { }çoklu ifadeleri aslında bir try-blok veya işleyici kullanıldığı durumlar hariç parantez. Örneğin, aşağıdakilere izin vermek önemsiz olurdu:

int f()
{
    return g() catch(xxii) { // not C++
        error("G() goofed: xxii");
        return 22;
    };
}

Ancak bunu, destek personelinin karışık kullanıcılardan kurtarması için yedekliliğin getirildiğini açıklamak zor buldum.

Düzenleme: Bunun neden kafa karıştırıcı olacağı konusunda, bence bir problem olacağını anlamak için @Tom Jeffery'nin cevabındaki (ve özellikle de aldığı oyların sayısındaki) yanlış iddialara bakmak gerekiyor. Ayrıştırıcı için, bu eşleştirme gerçekten farklı değil elses ile ifs - diğer bir gruba zorla parantez eksik, tüm catch maddeleri En son ile eşleşir throw. İçerdiği misbegotten dilleri için finallymaddeler aynı şeyi yapar. Ayrıştırıcının bakış açısına göre, bu durumun mevcut durumdan farkına varmaktan yeterince farklı değildir - özellikle gramerler şu anda durduğunda, catchcümleleri bir araya getirmek için gerçekten hiçbir şey yoktur - parantezler, kontroller tarafından kontrol edilen ifadeleri gruplandırır.catch cümlecikler, catch cümleleri kendileri değil.

Ayrıştırıcı yazma bakış açısından, fark neredeyse farkedilmeyecek kadar küçüktür. Eğer böyle bir şeyle başlarsak:

simple_statement: /* won't try to cover all of this */
                ;

statement: compound_statement
         | simple_statement
         ;

statements: 
          | statements statement
          ;

compound_statement: '{' statements '}'

catch_arg: '(' argument ')'

O zaman aradaki fark şu olurdu:

try_clause: 'try' statement

ve:

try_clause: 'try' compound_statement

Aynı şekilde, yakalama cümleleri için:

catch_clause: 'catch' catch_arg statement

vs.

catch_clause: 'catch' catch_arg compound_statement

Tam bir deneme / yakalama bloğunun tanımının değişmesi gerekmez. Her iki şekilde de böyle bir şey olurdu:

catch_clauses: 
             | catch_clauses catch_clause
             ;

try_block: try_clause catch_clauses [finally_clause]
         ;

[Burada [whatever], isteğe bağlı bir şeyi belirtmek için kullanıyorum ve sözdizimi dışında bırakıyorum finally_clauseçünkü bu konuyla ilgili bir etkisi olmadığını düşünüyorum.]

Buradaki tüm Yacc benzeri dilbilgisi tanımını takip etmeyi denemeseniz bile, nokta oldukça kolay bir şekilde özetlenebilir: bu son ifade (başlayarak try_block), catchcümlelerin cümleciklerle eşleştirildiğidir try- ve aynen öyle kalır . Aynı şekilde parantez gerekli olsun veya olmasın.

/ Özetlemek yinelemek için: Birlikte parantez grubu kontrollü ifadeleri ilecatch s, ama yapacak değil grup catchkendilerini bu. Bu nedenle, bu parantezlerin hangisinin hangisiyle gideceğine karar vermede kesinlikle etkisi yoktur . Ayrıştırıcı / derleyici için görev her iki şekilde de aynı derecede kolaydır (veya zor). Buna rağmen, Tom'un cevap (ve Alındıktan yukarı-oy sayısı) @ Aslında böyle bir değişikliğin bol kanıtıdır olur neredeyse kesinlikle şaşırtmak kullanıcıları.catchtry


OP denemede hem etrafında parantez soruyor yakalama bloğunun bu görünür etrafında olanlar başvuru edilecek ise, denemede ... Teşekkür Can (ilk paragraf hem referans anlaşılabilir, ancak kodu yalnızca eski göstermektedir) netleştirmek?
Shog9

@ Mr.CRT: Bir "yakalama bloğu", aksi halde yukarıdaki alıntıyı gören bir "işleyici" olarak bilinir.
Jerry Coffin

3
bah, bu belirsizliği ortadan kaldırmak için yorumumu yeni düzenledi . Yaptığım şey, parantezsiz konstrüksiyonun nasıl çalıştığını göstermek için daha uzun sürdüğü takdirde Tom'un (yukarıdaki) 'den daha etkili bir cevap olabileceği , ancak kafa karıştırıcı bir şekilde (Billy'nin Tom'un cevabı üzerine yaptığı yorum. Bunun işe yaramadığını, ki bunun yanlış olduğuna inanıyorum).
Shog9

@JerryCoffin Cevabınızı genişlettiğiniz için teşekkür ederiz: Şimdi bana çok daha açık.

try return g(); catch(xxii) error("G() goofed: xxii");hala temiz
olmalıydı

19

Gelen parantez bazı tek tablo yapılarının fakat diğerleri için gereklidir neden bir cevap Eric Lippert yazdı:

"Çıplak" bir ifadeye izin vermek yerine C # 'nin hazır bir ifade bloğu gerektirdiği çok sayıda yer var. Onlar:

  • bir yöntem, yapıcı, yıkıcı, mülk erişimcisi, olay erişimcisi veya dizin oluşturucu erişimcisi.
  • bir deneme bloğu, nihayet kontrol edildi, kontrol edilmedi veya güvensiz bir bölge yakalayın.
  • deyim lambda bloğu veya anonim yöntem
  • blok doğrudan yerel değişken bildirimi içeriyorsa, bir if veya loop deyiminin bloğu. (Yani, "while (x! = 10) int y = 123;" yasa dışıdır; bildirimi hazırlamanız gerekir.)

Bu vakaların her birinde, tek bir açıklanmamış ifadenin yasal olduğu özellik için belirsiz bir dilbilgisi (veya belirsiz bir dilbilgisini açıklığa kavuşturma sezgiselliği) ile gelmek mümkün olacaktır. Fakat mesele ne olurdu? Bu durumların her birinde birden fazla ifade görmeyi bekliyorsunuz; tekli ifadeler nadir, olası bir durum değildir. Bu olası durumlar için dilbilgisini açık hale getirmek gerçekten değmez gibi görünüyor.

Başka bir deyişle, derleyici ekibin uygulayacağı marjinal fayda için gerekçelendirilenden daha uygulaması pahalıydı.


13

Bence başka stil sorunlarından sarkmaktan kaçınmak. Aşağıdaki belirsiz olurdu ...

try
    // Do stuff
try
    // Do  more stuff
catch(MyException1 e1)
    // Handle fist exception
catch(MyException2 e2)
    // So which try does this catch belong to?
finally
    // and who does this finally block belong to?

Bu şu anlama gelebilir:

try {
   try {

   } catch(Exception e1) {

   } catch(Exception e2) {

   } 
} finally {

} 

Veya...

try {
   try {

   } catch(Exception e1) {

   } 
} catch(Exception e2) {

} finally {

} 

24
Bu belirsizlik için geçerlidir eğer ve için eşit. Soru şu: Neden if ve switch ifadesine izin veriliyor, ancak denemek / yakalamak için izin veriliyor ?
Dipan Mehta

3
@Dipan fuar noktası. Merak ediyorum, basitçe Java / C # 'nın diş telsiz olmayan ifs' e izin vererek C gibi eski dillerle uyumlu olmaya çalışmasının bir meselesi olup olmadığını merak ediyorum. Oysa dene / yakala daha yeni bir yapı olsa da, dil tasarımcıları geleneği bozmanın doğru olduğunu düşünüyorlardı.
Tom Jefferys

En azından C ve C ++ için zorlamayı cevaplamaya çalıştım.
Dipan Mehta

6
@DipanMehta: Çünkü ifdava için birden fazla muhtemel sarkan başka maddeler yok . Sadece "eğer varsa en içteki yere bağlanır" demek kolaydır ve bununla bitirin. Ama bu işe yaramazsa denemek / yakalamak için.
Billy ONeal

2
@Billy: Eğer varsa / eğer varsa potansiyel belirsizliği aydınladığınızı düşünüyorum ... "Söylemesi kolay" demek kolaydır - ama bu, tesadüfen, izin vermeyen belirsizliği çözmek için zor bir kural olduğu için parantez kullanılmadan bazı yapılar. Jerry'nin cevabı, bunun kafa karışıklığını önlemek için yapılan bilinçli bir seçim olduğu anlamına geliyor , ancak kesinlikle işe yarayabilirdi - tıpkı eğer / eğer varsa "işe yarıyor".
Shog9

1

Bence asıl sebep, C # 'da yapabileceğiniz çok az şeyin sadece bir satır olan bir deneme / yakalama bloğuna ihtiyacı olduğunu düşünüyorum. (Şu an kafamın en üstünde hiçbir şey düşünemiyorum). Catch bloğu açısından geçerli bir noktaya sahip olabilirsiniz, örneğin bir şeyi günlüğe kaydetmek için bir satırlık bir ifade olabilir, ancak okunabilirlik açısından {} gereksinim duymak daha mantıklı olur.

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.