Soldan sağa dil sözdiziminin avantajları


18

Channel9'da Herb Sutter ile bir röportaj izledim ve videonun sonunda, soldan sağa sözdiziminin gelecekteki bir C ++ standardı için whishlist'in üstünde olacağını söyledi (ancak C ++ 'ı değiştirmenin bu şekilde olduğunu kabul etse de) tamamen farklı bir canavar yaratır).

Dışında:

  • çıplak gözle daha açık, insanlar tarafından daha anlaşılır;

    //C syntax
    
    /*pointer to function taking a pointer to function(which takes 2 integers as 
    
    arguments and returns an int), and an int as arguments and returning an int*/
    
    int (*fp)(int (*ff)(int x, int y), int b)
    
    //Go analogous syntax which is left to write
    
    f func(func(int,int) int, int) int
  • ayrıştırması daha kolay (videoda belirtildiği gibi daha iyi araç desteğine yol açar - örneğin kod yeniden düzenleme)

bir programlama dilinde "soldan sağa" sözdizimi ile başka avantajlar da vardır. Sadece Pascal ve Go'nun bu tür bir sözdizimini kullanmasını biliyorum (ve Go , örnekleri de aldığım bu blog yazısından anladığım kadarıyla bile tam yoldan gitmiyor ) Bu tür bir sistem programlama diline sahip olmak mümkün olur mu sözdizimi


1
haskell soldan sağa kullanır:f :: (Int -> Int -> Int) -> Int -> Int
Karoly Horvath

1
Yanı ActionScript: function strlen(s:String):int {...}. Ayrıca, yazılan lambda hesabı (dolayısıyla Haskell).
outis

2
Herkes kapanış oyları açıklayabilir misiniz :)? Kapatmak için herhangi bir neden göremiyorum ama belki de "yanlış" bir soru soruyorum.

1
Kapatmak için oy vermedim, ancak @Devjosh tarafından yapılan yorum uygun, Programcılar için daha uygun, umarım birisi göç edecek ....
Nim

3
@Frank: ve işlev işaretçileri sözdizimi sözdiziminin garip olduğunu unutmayın, çünkü gerçek tür ayrılmıştır ! Bu düşük bir darbe ...
Matthieu M.

Yanıtlar:


12

Temel avantaj ayrıştırma işleminin daha basit ve benzersiz olmasıdır. Satır ayrıştırıldıktan sonra, derleyicinin tam türün ne olduğunu bileceğini, bu nedenle oradan türün nasıl tanımlandığının önemsiz olduğunu unutmayın.

Dizi türü veya işlev işaretçisi türünün bağımsız değişkenini döndüren herhangi bir işlevi şu anda okumak zor:

// common way of obtaining the static size in elements of an array:
template <typename T, int N>
char (&array_size_impl( T (&)[N] ))[N];
// alternative parser:
template <typename T, int N>               // this would probably be changed also
array_simple_impl function( T [N] & ) char [N] &;

Ve yanlış anlama için daha az şans olurdu ( en can sıkıcı-ayrıştırma olarak ):

// Current C++
type x( another_type() );      // create an instance x of type passing a
                               // default constructed another_type temporary?
                               // or declare a function x that returns type and takes as argument
                               // a function that has no arguments and returns another_type
// How the compiler reads it:
x function( function() another_type ) type;

// What many people mean:
x type { another_type{} };

C ++ 0x'de muntazam başlatma için benzer bir yaklaşım kullanarak ( {}başlatma işlemini tanımlamak için). Soldan sağa bir yaklaşımla, tanımladığımız şeyin çok daha net olduğunu unutmayın. Birçok insan (kesin olarak) geçmişte bu ayrıştırma hatasıyla (bir kereden fazla) herhangi bir noktada ısırıldı ve soldan sağa sözdiziminde böyle olmazdı.


İfadelere ne dersiniz? Bu "soldan sağa sözdizimi" operatörün önceliğini ve değerlendirme sırasını nasıl etkiler?

1
@celavek: Röportaja geri dönerseniz, dilin söz diziminin tamamını, yalnızca bildirimleri ve tanımları değiştirmek istemediğini göreceksiniz . Tabii ki, diğer ifadelerde nüfuz edebilir, yukarıdaki örneklerde son satırın soldan sağa doğru olduğundan emin değilim (geçici olarak nasıl oluşturulduğunu düşünün, bu değiştirilmesi gerekebilir ...) C # C ++ için olduğu gibi C ++ için geçerli olmayan veya newoperatöre iki semantik verilerek çözülür - değer / referans türleri üzerinde hiçbir ayrım yokturstructclass
David Rodríguez - dribeas

5

Buraya Nasıl Geldik

İşlev noktalarını bildirmek için kullanılan C sözdiziminin kullanımı yansıtması amaçlanmıştır. Aşağıdaki gibi düzenli bir işlev bildirimi düşünün <math.h>:

double round(double number);

Bir nokta değişkenine sahip olmak için bunu tip güvenliği ile atayabilirsiniz.

fp = round;

bu fpnokta değişkenini şu şekilde beyan etmeniz gerekir :

double (*fp)(double number);

Yapmanız gereken tek şey Yani işlevini kullanın ve yapım bir işaretçi referansı ile bu işlevin adını yerini alacak nasıl bakmak roundiçine *fp. Bununla birlikte, bazılarının biraz daha karışık hale getirdiğini söyleyecek ekstra bir parens setine ihtiyacınız var.

Muhtemelen, bu işlev imzası bile olmayan orijinal C'de daha kolaydı, ama oraya geri dönmeyelim, tamam mı?

Özellikle kötü hale geldiği yer, bir argüman olarak alan veya bir işleve bir işaretçi döndüren bir işlevi veya her ikisini birden nasıl bildireceğini bulmaktır.

Bir fonksiyonunuz varsa:

void myhandler(int signo);

bunu sinyal fonksiyonuna (3) şu şekilde aktarabilirsiniz:

signal(SIGHUP, myhandler);

ya da eski işleyiciyi saklamak istiyorsanız,

old_handler = signal(SIGHUP, new_handler);

ki bu oldukça kolay. Oldukça kolay - ne güzel, ne de kolay - beyanları doğru yapmaktır.

signal(int signo, ???)

Eh, işlev bildiriminize geri dönün ve bir nokta referansı için adı değiştirin:

signal(int sendsig, void (*hisfunc)(int gotsig));

Beyan etmediğiniz için gotsig, atlarsanız okumayı daha kolay bulabilirsiniz:

signal(int sendsig, void (*hisfunc)(int));

Ya da olmayabilir. :(

Bunun yeterince iyi olmaması dışında, sinyal (3) de eski işleyiciyi aşağıdaki gibi döndürür:

old_handler = signal(SIGHUP, new_handler);

Şimdi tüm bunları nasıl ilan edeceğinizi anlamalısınız.

void (*old_handler)(int gotsig);

atayacağınız değişken için yeterlidir. gotsigSadece burada gerçekten beyan etmedığınızı unutmayın old_handler. Bu gerçekten yeterli:

void (*old_handler)(int);

Bu bizi sinyal (3) için doğru bir tanımlamaya getirir:

void (*signal(int signo, void (*handler)(int)))(int);

Kurtarmaya Tip Tanımlar

Bu zamana kadar herkesin bunun bir karmaşa olduğunu kabul edeceğini düşünüyorum. Bazen soyutlamalarınızı adlandırmak daha iyidir; sık sık, gerçekten. Doğru ile typedef, bunu anlamak çok daha kolay hale gelir:

typedef void (*sig_t) (int);

Artık kendi işleyici değişkeniniz

sig_t old_handler, new_handler;

ve sinyal (3) için beyanınız

sig_t signal(int signo, sig_t handler);

aniden anlaşılır. * 'Dan kurtulmak da kafa karıştırıcı parantezlerden bazılarını ortadan kaldırır (ve ebeveynlerin her zaman anlaşılmasını kolaylaştırdığını söylerler - hah!). Kullanımınız hala aynı:

old_handler = signal(SIGHUP, new_handler);

ama şimdi için bildirimleri anlama şansına sahip old_handler, new_handlerve hattasignal onları ilk veya ihtiyaç karşılaştıklarında onları yazmak için.

Sonuç

ÇokGörünüşe göre, az sayıda C programcısı, referans materyallere danışmadan bu şeyler için doğru beyanları kendileri tasarlayabiliyor.

Biliyorum, çünkü bir zamanlar çekirdek ve aygıt sürücüsü çalışması yapan kişiler için röportaj sorularımızda bu soruyu sorduk. :) Tabii, onlar beyaz tahta çöktü ve yandı gibi çok sayıda aday kaybettik. Ancak, bu alanda daha önce deneyime sahip olduklarını iddia eden, ancak işi yapamayacağını iddia eden kişileri işe almaktan kaçındık.

Bu yaygın zorluk nedeniyle, muhtemelen sadece mantıklı değil, aynı zamanda sadece bunu kullanmak için ortalamanın üzerinde üç sigma oturan bir üçlü alfa geek programcısı olmanızı gerektirmeyen tüm bu beyanları gözden geçirmenin bir yoluna sahip olmak muhtemelen mantıklıdır. bir şey rahatça.


1
Düzenli, takip edilmesi zor ... Çabada bazen doğru olmanın zor olduğu noktasını gösterdiği için çaba için +1
celavek

4

Soldan sağa biraz odaklandığınızda noktayı kaçırdığınızı düşünüyorum.

C ve C ++ problemleri, hem okunması (insanlar) hem de ayrıştırılması (araçları) zor olan korkunç grameridir.

Daha tutarlı (veya düzenli) ) bir dilbilgisine her ikisini de kolaylaştırır. Ve daha kolay ayrıştırma daha kolay takım anlamına gelir: mevcut araçların çoğu C ++ 'ı doğru almaz, tekerleği yeniden icat etmeye çalışırken en son Eclipse eklentisi bile değil ... ve başarısız oldu ve muhtemelen ortalama işletim sistemi projesinden daha fazla insana sahipler.

Yani muhtemelen okumaya ve ayrışmaya odaklanırken çivilenmiştiniz ... ve bu çok önemli :)


Eclipse'nin hala yukarıdaki beyanlar gibi şeyleri ayrıştıramaması büyük bir sürpriz. Neden gerçek bir C ayrıştırıcısı kullanmıyorlar gcc?
tchrist

@tchrist: Eclipse ile ilgili iki sorun tespit ettim ve her ikisi de makrolarla bağlantılı görünüyor. Belki de AST üretiminden daha fazla bir önişlemci sorunu.
Matthieu M.
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.