“Blub Paradoksu” ve c ++


37

Buradaki yazıyı okuyordum: http://www.paulgraham.com/avg.html ve "blub paradoksu" ile ilgili bölüm özellikle ilginçti. Çoğunlukla c ++ kodlayan ancak diğer dillere maruz kalan (çoğunlukla Haskell) biri olarak, bu dillerde c ++ dilinde çoğaltılması zor olan bazı yararlı şeylerin farkındayım. Asıl soru, hem c ++ hem de başka bir dilde yetkin kişiler için, sadece c ++ ile yazıyorsanız kavramsallaştırmak veya uygulamak zor olacak bir dilde kullandığınız güçlü bir dil özelliği veya deyim var mı?

Özellikle bu alıntı dikkatimi çekti:

İndüksiyonla, çeşitli diller arasındaki iktidardaki tüm farklılıkları görebilecek konumda olan tek programcılar en güçlü olanı anlayanlardır. (Muhtemelen Eric Raymond'ın Lisp'i daha iyi bir programcı yapması için kastettiği şey buydu.) Blub paradoksu nedeniyle diğerlerinin görüşlerine güvenemezsiniz: kullandıkları dilden memnunlar, çünkü kullandıkları dilin programlar hakkında düşünmenin yolu.

Eğer c ++ 'ı kullanarak "Blub" programcısının eşdeğeri olduğum ortaya çıkarsa, bu şu soruyu gündeme getirir: Başka dillerde karşılaştığınız, kavramsallaştırmakta zorlandığınız herhangi bir yararlı kavram veya teknik var mı? c ++ 'ta yazıyor veya "düşünüyor"?

Örneğin, Prolog ve Mercury gibi dillerde görülen mantık programlama paradigması, castor kütüphanesi kullanılarak c ++ 'ta uygulanabilir, ancak sonuçta kavramsal olarak Prolog kodu olarak düşündüğümü ve bunu kullanırken c ++ eşdeğerine çevirmeyi düşünüyorum. Programlama bilgimi genişletmenin bir yolu olarak, bir c ++ geliştiricisi olarak farkında olamayacağım başka dillerde daha verimli bir şekilde ifade edilen başka yararlı / güçlü deyimler örnekleri olup olmadığını bulmaya çalışıyorum. Akla gelen bir başka örnek lisp'teki makro sistemdir, program kodunu programın içinden çıkarmanın bazı problemler için birçok faydası var gibi görünüyor. Bunu uygulamak ve c ++ içinden düşünmek zor gibi görünüyor.

Bu soru, "c ++ vs lisp" tartışması veya herhangi bir dil savaşı türü tartışması değildir. Bunun gibi bir soru sormak, bilmediğim şeyler hakkında bilmediğim şeyleri öğrenmenin tek yoludur.



2
Katılıyorum. Bu C ++ vs Lisp tartışmasına dönüşmediği sürece burada öğrenilecek bir şey olduğunu düşünüyorum.
jeffythedragonslayer 10:11

@MasonWheeler: there are things that other languages can do that Lisp can't- Muhtemelen , çünkü Lisp Turing tamamlandı. Belki de Lisp'te yapmakta pratik olmayan bazı şeyler olduğunu söylemek istediniz? Herhangi bir programlama dili için aynı şeyi söyleyebilirim .
Robert Harvey,

2
@RobertHarvey: "Tüm diller, Turing'in eşdeğeri olma anlamında eşit derecede güçlüdür, ancak programcıların umursadığı kelimenin anlamı yoktur. (Hiç kimse bir Turing makinesini programlamak istemez.) resmi olarak tanımlanabilir, ancak bunu açıklamanın bir yolu, onun içinde daha güçlü bir dil için bir tercüman yazarak ancak daha az güçlü bir dilde elde edebileceğiniz özellikleri ifade ettiğini söylemektir. ” - Paul Graham, söz konusu trol direğine bir dipnotta. (Ne demek istediğimi anladın mı?)
Mason Wheeler

@Mason Wheeler: (Gerçekten değil.)
Robert Harvey,

Yanıtlar:


16

Haskell'den bahsettiğinden beri:

  1. Desen Eşleştirme. Desen eşleşmesinin okunması ve yazılması çok daha kolay. Haritanın tanımını göz önünde bulundurun ve model eşleşmesi olmadan bir dilde nasıl uygulanacağını düşünün.

    map :: (a -> b) -> [a] -> [b]
    map f [] = []
    map f (x:xs) = f x : map f xs
  2. Tip sistemi. Bazen bir ağrı olabilir ama çok faydalıdır. Gerçekten onu anlamak ve onunla kaç tane böcek yakaladığını programlamak zorundasın. Ayrıca, referans şeffaflığı harika. Sadece Haskell'de programlandıktan sonra bir süre için zorunlu bir dilde durumun yönetilmesinden kaç hata oluştuğu ortaya çıkıyor.

  3. Genel olarak fonksiyonel programlama. Yineleme yerine haritalar ve katlamalar kullanma. Özyineleme. Daha yüksek seviyede düşünmekle ilgili.

  4. Tembel değerlendirme. Yine daha üst düzeyde düşünmek ve sistemin değerlendirmeyi ele almasına izin vermekle ilgilidir.

  5. Cabal, paketler ve modüller. Benim için Cabal indirme paketlerine sahip olmak, kaynak kodunu bulmak, bir makefile yazmak vb. İçin çok daha uygundur.


2
Desen eşleşmesi üzerine bir not: Genel olarak yazmanın daha kolay olduğunu söyleyemem, ancak ifade problemini biraz okuduktan sonra, eğer if ve switch ifadeleri, enums ve gözlemci deseninin Cebirsel Veri Tiplerinin aşağılık uygulamaları olduğu açıktır. + Desen Eşleştirme. (Ve belki de nasıl boş gösterici istisnalarını eskimiş hale getirdiği konusunda bile başlamayalım)
hugomg

Söylediğiniz doğru, ancak ifade sorunu cebirsel veri türlerinin kısıtlamaları (ve standart OOP'un ikili kısıtlamaları) ile ilgili.
Blaisorblade

@hugomg Bunu mu demek istediniz: Observer
Sebastian Redl

Evet. Her zaman bu iki ismi değiştiririm :)
hugomg

@hugomg Maybe(C ++ görmek için std::optional) sahip olmakla ilgili değil, açık bir şekilde isteğe bağlı / nullable / maybe olarak işaretlemek zorunda.
Deduplicator

7

Memoize!

C ++ ile yazmayı deneyin. C ++ 0x ile değil .

Çok hantal mı? Tamam, C ++ 0x ile deneyin .

Bu 4-satırlı (veya 5-satır, her neyse: P) derleme zamanı sürümünü D:

auto memoize(alias Fn, T...)(T args) {
    auto key = tuple(args);                               //Key is all the args
    static typeof(Fn(args))[typeof(key)] cache;           //Hashtable!
    return key in cache ? cache[key] : (cache[key] = Fn(args));
}

Aramak için tek yapmanız gereken şöyle bir şey:

int fib(int n) { return n > 1 ? memoize!(fib)(n - 1) + memoize!(fib)(n - 2) : 1;}
fib(60);

Aynı zamanda Scheme'de de benzer bir şey deneyebilirsiniz, ancak çalışma zamanında gerçekleşmesi biraz daha yavaş olsa da ve buradaki arama karma yerine doğrusal (ve de, çünkü Scheme):

(define (memoize f)
    (let ((table (list)))
        (lambda args
            (cdr
                (or (assoc args table)
                    (let ((entry (cons args (apply f args))))
                        (set! table (cons entry table))
                        entry))))))
(define (fib n)
        (if (<= n 1)
            1
            (+ (fib (1- n))
                (fib (- n 2)))))))
(set! fib (memoize fib))

1
Yani tek bir satırda herhangi bir şeyi yazabileceğiniz APL'yi seviyorsunuz? Boyut önemli değil!
Bo Persson

@Bo: APL kullanmadım. "Boyut önemli değil" derken neyi kastettiğinizden emin değilim, ancak kodumu size söyleyen yanlış bir şey var mı? Ve bunun farkında olmadığınız farklı bir dilde (C ++ gibi) nasıl yapılacağının bir avantajı var mı? (Değişken isimlerini biraz düzelttim, belki de bahsettiğiniz şeydi.)
Mehrdad

1
@Mehrdad - En kompakt program hakkında yorumum en iyi programlama dilinin işareti değildir. Bu durumda APL elleri kaybeder, çünkü çoğu şeyi tek bir char operatörüyle yaparsınız. Tek sorun, okunamaz olması.
Bo Persson

@Bo: Dediğim gibi, APL'yi tavsiye etmiyordum; Daha önce hiç görmedim. Boyut bir kriterdi (C ++ ile bunu denerseniz görebileceğiniz gibi önemli olmasına rağmen) ... ama bu kodda yanlış bir şey var mı?
Mehrdad

1
@Matt: Kodunuz bir işlevi hafızaya aldı , ancak bu kod herhangi bir işlevi hafızaya alabilir . Bunlar hiç de eşdeğer değil. Aslında C ++ 0x'te bunun gibi daha üst düzey bir işlev yazmayı denerseniz, D'den çok daha sıkıcı olur (yine de oldukça mümkündür ... ancak C ++ 03'te mümkün olmasa da).
Mehrdad

5

C ++, bir çok paradigma dilidir; bu, birçok düşünme biçimini desteklemeye çalıştığı anlamına gelir. Bazen bir C ++ özelliği, işlevsel programlamada olduğu gibi başka bir dilin uygulamasından daha garip veya daha az akıcıdır.

Bu, yieldPython veya JavaScript’te ne yaptığını yapan yerel bir C ++ dili özelliğinin başımın üstünde olduğunu düşünemiyorum .

Diğer bir örnek, eşzamanlı programlamadır . C ++ 0x hakkında bir söz sahibi olacak, ancak mevcut standart yok ve eşzamanlılık tamamen yeni bir düşünce tarzı.

Ayrıca, hızlı gelişim - hatta kabuk programlama - C ++ programlama alanından asla ayrılmazsanız asla öğrenemeyeceğiniz bir şeydir.


C ++ 2003'te C ++ 'ta jeneratör üretmenin ne kadar zor olduğunu düşünmeye bile başlayamıyorum. C ++ 2011 işleri kolaylaştıracak, ancak önemsiz şeyler yapacaktır. C ++, C # ve Python ile düzenli olarak çalışan jeneratörler, C ++ 'da en çok özlediğim özellik (kolayca;

Bunun için vurulacağımı biliyorum, fakat kesinlikle jeneratörleri C ++ 'ta uygulamak zorunda olsaydım, kullanmak zorunda kalırdım ... setjmpve longjmp. Ne kadar kırıldığına dair hiçbir fikrim yok, ancak istisnalar ilk giden olabilir. Şimdi, izin verirseniz, bunu kafamdan çıkarmak için Modern C ++ Design'ı tekrar okuman gerekiyor .
Mike DeSimone 10:11

@Mike DeSimone, setjmp ve longjmp ile nasıl bir çözüm bulmaya çalışacağınızı ayrıntılı olarak açıklayabilir misiniz?

1
Korotinler, functors için izomorfiktir.
GManNickG

1
@Xeo, @Mike: xkcd.com/292
Mehrdad

5

Coroutinler , C ++ 'dan diğer dillerin daha somut faydalarını destekleyen, oldukça faydalı bir dil özelliğidir. Temelde ekstra yığınlar sağlarlar, böylece fonksiyonların kesintiye uğraması ve devam etmesi sağlanır; böylece işlem sonuçlarını filtrelerden diğer işlemlere kolayca aktaran dile boru hattı benzeri tesisler sağlanır. Harika, ve Ruby'de çok sezgisel ve zarif buldum. Tembel değerlendirme de buna bağlı.

Introspection ve çalışma zamanı kodu derleme / yürütme / değerlendirme / C ++ 'nın sahip olmadığı kitlesel olarak güçlü özellikler.


Coroutinler, C'ye uygulanan FreeRTOS'ta ( buraya bakın ) mevcuttur, merak ediyorum, C ++ 'da çalışmasını sağlamak için ne gerekir?
Mike DeSimone 10:11

Ortak rutinler, C'deki nesneleri taklit etmek için çok kötü bir saldırıdır. C ++ 'da, nesneler kod ve verileri paketlemek için kullanılır. Ama C’de yapamazsın. Böylece, verileri saklamak için ortak rutin yığınını ve kodu tutmak için ortak rutin işlevini kullanırsınız.
MSalters


1
@Ferruccio: Bağlantı için teşekkürler ... Wikipedia makalesinde de birkaçı var. @ MSalters: eş rutinleri "iğrenç bir kesmek" olarak nitelendiren nedir? Bana çok keyfi bir bakış açısı geliyor. Aynı zamanda özyinelemeli algoritmalar tarafından yapılan durumu depolamak için bir yığın kullanmak - onlar da hack mi? FWIW, coroutines ve OOP, aynı zamanda (1960'ların başlarında) aynı olay yerine geldiler. > C ++ 'dan 15 yıl önce.
Tony,

4

Hem Lisp hem de C ++ 'da bir bilgisayar cebir sistemi uyguladıktan sonra, lisan konusunda tamamen acemi olmama rağmen, Lisp'te görevin çok daha kolay olduğunu söyleyebilirim. Listelenen her şeyin bu basit doğası birçok algoritmayı basitleştirir. Verilmiş, C ++ sürümü zillions kat daha hızlıydı. Evet, lisp versiyonunu daha hızlı yapabilirdim, ama kod lispy kadar olmazdı. Scripting her zaman daha kolay olacak başka bir şey, örneğin lisp. Her şey iş için doğru aracı kullanmakla ilgili.


Hızdaki fark neydi?
quant_dev

1
@quant_dev: Elbette bir zilyonun bir katı!
Matt Ellen

Bunu asla ölçmedim ama büyük O'ların farklı olduğunu hissediyorum. Başlangıçta C ++ sürümünü işlevsel bir tarzda yazdım ve yeni, değiştirilmiş olanları oluşturmak yerine veri yapılarını değiştirmeyi öğretene kadar hız sorunları yaşadım. Ama bu aynı zamanda kodu okumayı zorlaştırdı ...
jeffythedragonslayer

2

Bir dilin diğerinden daha "güçlü" olduğunu söylerken ne demek istiyoruz? Bir dilin "etkileyici" olduğunu söylediğimizde Veya "zengin"? Ben düşünüyorum hayır, gerçekten bir durum geçişine - size kendi saha yeterince daraltır bir dil kazançlar güç kolay ve doğal bir sorunu açıklamak için yapmak anlamına? - bu görüş içinde yaşar. Ancak bu dil, görüş alanımız genişlediğinde, daha az güçlü, daha az anlamlı ve daha az kullanışlıdır.

Dil ne kadar "güçlü" ve "anlamlı" ise, kullanımı o kadar sınırlıdır. Bu yüzden belki "güçlü" ve "etkileyici", dar bir araç için kullanılabilecek yanlış kelimelerdir. Belki "uygun" veya "soyut" bu tür şeyler için daha iyi kelimelerdir.

Bir sürü düşük seviye malzeme yazarak programlamaya başladım: kesme yordamlarına sahip aygıt sürücüleri; gömülü programlar; işletim sistemi kodu. Kod, donanıma özgüydi ve hepsini assembly dilinde yazdım. Birleştiricinin en az soyut olduğunu söyleyemeyiz, yine de hepsinin en güçlü ve en etkileyici diliydi. Assembly dilinde herhangi bir problemi ifade edebilirim; O kadar güçlü ki, herhangi bir makinede istediğim her şeyi yapabilirim.

Ve daha sonra üst düzey dil anlayışımın tümü, assembler deneyimimdeki her şeye borçludur. Daha sonra öğrendiğim her şey kolaydı, çünkü görüyorsunuz, her şey - ne kadar soyut olursa olsun - sonunda donanıma uyum sağlamak zorunda.

Daha yüksek ve daha yüksek soyutlama seviyelerini unutabilirsiniz - yani daha dar ve daha dar görüş alanları. Bunu daha sonra alabilirsin. Öğrenmek çok zor, birkaç gün içinde. Bence, donanım 1'in dilini öğrenmek , kemiğe mümkün olduğu kadar yaklaşmak daha iyi olurdu .


1 Belki oldukça dair değildir, ancak carve cdrdonanım ismini almaktadır: İlk Lisp gerçek Azaltma Kayıt ve gerçek Adres Kayıt vardı bir makinede koştu. Buna ne dersin?


Bu seçimin iki taraflı bir kılıç olduğunu görüyorsunuz. Hepimiz onu arıyoruz, ama karanlık bir tarafı var ve bu bizi mutsuz ediyor. Dünyayı ve işletebileceğiniz sınırlarını tanımlayan çok iyi bir görüşe sahip olmak daha iyidir. İnsanlar çok yaratıcı yaratıklar ve sınırlı araçlarla harika şeyler yapabilirler. Özetlemek gerekirse, onun programlama dili olmadığını söylüyorum, ancak herhangi bir dili şarkı söyleyebilecek yetenekli insanlara sahip olduğumu söylüyorum!
Çad,

"Önermek yaratmaktır; tanımlamak yıkmaktır." Başka bir dille hayatı kolaylaştıracağını düşünmek iyi hissettiriyor, ancak bir kez atladığınızda, o zaman yeni dilin siğilleri ile başa çıkmak zorundasınız.
Mike DeSimone

2
İngilizcenin herhangi bir programlama diline göre çok daha güçlü ve etkileyici olduğunu söyleyebilirim, ancak kullanımının sınırları her gün genişliyor ve faydası çok büyük. Gücün ve ifadenin bir kısmı, uygun soyutlama düzeyinde iletişim kurabilmekten ve birleştirildiğinde yeni soyutlama seviyelerini icat edebilmekten gelir.
molbdnilo

@Mike o zaman yeni dilde önceki dil ile iletişim kurmanız gerekir;)
Çad

2

İlişkisel Diziler

Verilerin işlenmesinin tipik bir yolu:

  • girişi okumak ve ondan hiyerarşik bir yapı oluşturmak,
  • bu yapı için indeksler oluşturmak (örneğin farklı sıralar),
  • bunların özütlerini (filtrelenmiş parçalar) oluşturmak
  • bir değer veya değer grubunu bulma (düğüm),
  • yapıyı yeniden düzenleme (düğümleri silme, ekleme, ekleme, kurala dayalı alt öğeleri kaldırma vb.),
  • ağaçtan tarayın ve bazı kısımlarını yazdırın veya kaydedin.

Bunun için doğru araç, ilişkisel dizidir .

  • Gördüğüm ilişkisel diziler için en iyi dil desteği, ilişkisel dizilerin olduğu MUMPS'dir : 1. her zaman sıralanır 2. aynı sözdizimiyle diskte (veritabanı adı verilen) oluşturulabilirler. (Yan etkisi: veritabanı olarak son derece güçlü, programcı yerli btree erişebilir. Şimdiye kadarki en iyi NoSQL sistemi.)
  • İkincilik ödülü PHP'ye gidiyor , $ a [] = x veya $ a [x] [y] [z] ++ gibi foreach ve kolay sözdizimlerini seviyorum .

JavaScript'in ilişkisel dizi sözdizimini gerçekten sevmiyorum, çünkü oluşturamıyorum, [x] [y] [z] = 8 , önce bir [x] ve [x] [y] oluşturmak zorundayım .

Tamam, C ++ 'da (ve Java'da) güzel konteyner sınıfları portföyü var, Harita , Multimap , her neyse, ama eğer taramak istersem, bir yineleyici yapmalıyım ve yeni bir derin seviye elemanı eklemek istediğimde, tüm üst seviyeleri yaratmalıyız. Rahatsız edici.

C ++ (ve Java) 'da kullanılabilir bir ilişkisel dizi olmadığını söylemiyorum, fakat yazımsız (veya katı olmayan yazılan) betik dilleri derlenmiş dilleri atıyor, çünkü yazımsız script dilleri.

Feragatname: C # ve diğer .NET dillerine aşina değilim, AFAIK iyi ilişkisel dizi kullanımına sahipler.


1
Tam açıklama: MUMPS herkes için değildir . Alıntı: MUMPS olan dehşete biraz daha “gerçek dünya” örneği vermek için, bir bölüm Uluslararası Şaşırtılmış C Kodu Yarışması, bir Perl işareti, FORTRAN ve SNOBOL’un iki öbek ölçüsü, ve bağımsız ve koordine olmayan katkılarından onlarca tıp araştırmacısı ve işte gidiyorsunuz.
Mike DeSimone

1
Python'da yerleşik dicttürden birini kullanabilirsiniz (örneğin x = {0: 5, 1: "foo", None: 500e3}, anahtarların veya değerlerin aynı tür olması gerekmediğine dikkat edin). Bir şey yapmayı denemek a[x][y][z] = 8zordur, çünkü dilin bir değer belirleyip belirleyemeyeceğinizi görmek için geleceğe bakması gerekir; ifade a[x][y]tek başına size söylemez.
Mike DeSimone

MUMPS başlangıçta ilişkisel dizilere sahip bir Temel benzeri dildir (doğrudan diskte depolanabilir!). Daha sonraki sürümler, çekirdeği PHP'ye çok benzeyen yordamsal uzantıları içerir. Basic ve PHP'den korkan biri Mumps'u korkutucu bulmalı, ancak diğerleri bilmiyor. Programcılar yapmaz. Unutmayın, çok eski bir sistem, tek harfli talimatlar (garip, tam adlar kullanabilirsiniz), LR değerlendirme düzeni vb. Gibi garip şeyler - ve garip olmayan çözümlerin - tek bir amacı var: optimizasyon .
ern0

“Küçük etkinlikleri unutmalıyız, zamanın yaklaşık% 97'sini söyleyelim: erken optimizasyon tüm kötülüklerin köküdür. Ancak bu kritik% 3'teki fırsatlarımızı kaçırmamalıyız.” - Donald Knuth. Tanımladığınız şey, bana geriye dönük uyumluluk olan eski bir dil gibi geliyor ve bu sorun değil. Şahsen, bu uygulamalarda, sürdürülebilirliği optimizasyondan daha önemli görüyorum ve cebirsel olmayan ifadeler ve tek harfli komutlar içeren bir dil verimsiz geliyor. Ben müşteriye hizmet ediyorum, dile değil.
Mike DeSimone

@Mike: gönderdiğiniz çok eğlenceli bağlantılar, onları okurken iyi bir kahkaha yaşadım.
shuttle87

2

Java, C \ C ++, Assembly ve Java Script öğelerini öğrenemiyorum. C ++ 'ı geçimim için kullanıyorum.

Yine de, Meclis programlamasını ve C programlamasını daha çok sevdiğimi söylemek zorunda kalacağım. Bu daha çok zorunlu programlama ile aynıdır.

Programlama Paradigmalarının veri tiplerini kategorize etmek için önemli olduğunu biliyorum ve güçlü tasarım kalıpları ve kodun formalizasyonuna izin vermek için daha yüksek programlama özetli kavramlar verdim. Her ne kadar bir anlamda, her Paradigma, altta yatan donanım katmanını soyutlamak için desen ve koleksiyonlardan oluşan bir koleksiyondur, bu nedenle makinenin içindeki EAX veya IP hakkında düşünmeniz gerekmez.

Bununla ilgili tek sorunum, halkın makinenin nasıl ideolojiye dönüştürüldüğü konusundaki fikir ve kavramlarına ve olup bitenlerin belirsiz iddialarına izin vermesidir. Bu ekmek, programcının bir ideolojisi amacına yönelik özetler üzerine yapılan her türlü harika soyutlamaları içerir.

Günün sonunda, CPU'nun ne olduğu ve bilgisayarların başlık altında nasıl çalıştığı konusunda net bir zihniyet ve sınırlara sahip olmak daha iyidir. İşlemcinin tek umurunda olduğu şey, verileri hafızanın içine ve dışına bir kayıt defterine taşıyan ve bir talimatı gerçekleştiren bir dizi talimatı uygulamaktır. Veri türü kavramı veya daha yüksek programlama kavramları yoktur. Yalnızca verileri dolaşır.

Programlama paradigmalarını karışıma eklediğinizde daha karmaşık hale gelir, çünkü dünyaya bakışımız tamamen farklıdır.


2

Sadece c ++ ile yazıyorsanız, kavramsallaştırması veya uygulaması zor bir dilde kullandığınız bazı güçlü dil özellikleri veya deyimler var mı?

Diğer dillerde, c ++ 'da yazmış veya "düşünmüş" olsanız, kavramsallaştırması zor olan herhangi bir yararlı kavram veya teknik var mı?

C ++ birçok yaklaşımı anlaşılmaz kılar. Kendinizi C ++ ile sınırlarsanız, programlamanın çoğunun kavramsallaştırmanın zor olduğunu söyleyecek kadar ileri giderdim. İşte C ++ 'ın zorlaştırdığı yollarla çok daha kolay çözülen bazı problem örnekleri.

Kayıt tahsisi ve arama kuralları

Pek çok insan C ++ 'ı basit bir metal düşük seviye dili olarak düşünür, ancak gerçekten değildir. C ++, makinenin önemli ayrıntılarını uzaklaştırarak, kayıt tahsisi ve çağrı sözleşmeleri gibi pratiklikleri kavramsallaştırmayı zorlaştırır.

Bunun gibi kavramlar hakkında bilgi edinmek için, bazı meclis dili programlarına göz atmanızı ve ARM kodu oluşturma kalitesiyle ilgili bu makaleyi gözden geçirmenizi öneririm .

Çalışma zamanı kodu üretimi

Eğer sadece C ++ 'ı biliyorsanız, muhtemelen şablonların metaprogramlamanın tümü ve sonu olduğunu düşünürsünüz. Onlar değil. Aslında metaprogramlama için nesnel olarak kötü bir araçtır. Başka bir programı manipüle eden herhangi bir program, tercümanlar, derleyiciler, bilgisayar cebir sistemleri ve teorem ispatlarını içeren bir metaprogramdır. Çalışma zamanı kodu üretimi bunun için yararlı bir özelliktir.

Bir Scheme uygulamasını başlatmanızı ve EVALmetakirküler değerlendirme hakkında bilgi edinmek için oynamayı tavsiye ederim .

Ağaçları manipüle etme

Ağaçlar programlamada her yerdeler. Ayrıştırmada soyut sözdizimi ağaçlarınız var. Derleyicilerde ağaç olan IR'ler var. Grafik ve GUI programlamada sahne ağaçlarınız var.

Bu "C ++ için gülünç derecede basit JSON Parser" , C ++ için çok küçük olan sadece 484 LOC'de. Şimdi , sadece F # 60 LOC ağırlığında olan kendi basit JSON ayrıştırıcımla karşılaştırın . Buradaki fark, öncelikle ML'nin cebirsel veri türleri ve desen eşleştirmesi (aktif desenler dahil), ağaçların işlenmesini oldukça kolaylaştırır.

OCaml'daki kırmızı-siyah ağaçları da kontrol edin .

Tamamen işlevsel veri yapıları

C ++ 'da GC eksikliği, bazı faydalı yaklaşımların benimsenmesini neredeyse imkansız hale getirir. Tamamen işlevsel veri yapıları böyle bir araçtır.

Örneğin, bu 47 satırlık düzenli ifade eşleştiricisini OCaml’de kontrol edin . Kısalık, büyük ölçüde tamamen işlevsel veri yapılarının yoğun kullanımından kaynaklanmaktadır. Özellikle, ayarlanan anahtarlarla sözlük kullanımı. C ++ 'da bunu yapmak çok zor çünkü stdlib sözlükleri ve kümeleri değişkendir, ancak bir sözlüğün anahtarlarını değiştiremezsiniz veya koleksiyonu bozursunuz.

Mantıksal programlama ve geri alma arabellekleri, yalnızca işlevsel veri yapılarının C ++ 'da zor olan bir şeyi diğer dillerde gerçekten kolaylaştırdığı diğer pratik örneklerdir.

Kuyruk çağrıları

C ++ yalnızca kuyruk çağrılarını garanti etmiyor, aynı zamanda RAII temelde sorunlara da karşı çıkıyor, çünkü yıkıcılar kuyruk konumunda bir çağrıya giriyor. Kuyruk çağrıları, yalnızca sınırlı miktarda yığın alanı kullanarak sınırsız sayıda işlev çağrısı yapmanızı sağlar. Bu, genişletilebilir durum makineleri de dahil olmak üzere devlet makinelerini uygulamak için harikadır ve pek çok garip durumda, harika bir "hapisten çıkma" kartıdır.

Örneğin , finans sektöründe F # 'deki not verme ile devam eden geçiş stilini kullanarak 0-1 sırt çantası probleminin bu uygulamasını kontrol edin . Kuyruk çağrılarınız olduğunda, devam eden geçiş tarzı açık bir çözüm olabilir, ancak C ++ bunu anlaşılmaz kılar.

eşzamanlılık

Diğer bir belirgin örnek, eşzamanlı programlamadır. Her ne kadar bu C ++ 'da tamamen mümkün olsa da, diğer araçlara kıyasla son derece hataya açıktır, sırayla Erlang, Scala ve F # gibi dillerde görüldüğü gibi sıralı işlemleri iletir.


1

Bu eski bir sorudur, ancak hiç kimse bundan bahsetmediğinden, liste (ve şimdi dict) anlamalarını ekleyeceğim. Fizz-Buzz problemini çözen Haskell veya Python'da bir liner yazmak kolaydır. Bunu C ++ 'da yapmayı deneyin.

C ++, C ++ 11 ile moderniteye büyük hareketler yaparken, buna "modern" bir dil demesi biraz zor. C ++ 17 (henüz yayınlanmadı), "modern", önceki bin yılda değil "anlamına geldiği sürece, modern standartlara ulaşmak için daha fazla hamle yapıyor."

Python'da bir satırda yazabileceği en basit kavrayışlar bile (ve Guido'nun 79 karakter satır uzunluğu sınırına uyarak), C ++ 'ya çevrildiğinde çok ve çok sayıda kod satırı olur ve bu C + + kodlarının bazı satırları oldukça kıvrımlıdır.


İyi not: Programlamamın çoğu C ++ dilinde. Dili severim
David Hammen

Aralık Teklifinin bunu çözmesi gerektiğini düşündüm? (Sanırım C ++ 17'de bile değil)
Martin Ba

2
“Moderniteye büyük hareketler”: C ++ 11'in mevcut bin yılda ne gibi “modern” özellikleri var?
Giorgio

@MartinBa - "Aralıklar" önerisini anladığımda, çalışması daha kolay ve daha az hataya neden olan yineleyiciler için bir ikame var. Liste anlama gibi ilginç bir şeye izin verebilecek herhangi bir öneri görmedim.
Jules

2
@Giorgio - şu anki binyılda popüler olan herhangi bir dilin hangi özellikleri icat edildi?
Jules

0

Kullanıcı tanımlı bir sınıfın kullanıcı tanımlı bir üye işlevi olan bir geri çağırma çağrısı derlenmiş bir kitaplık.


Bu, Objective-C'de mümkündür ve kullanıcı arayüzü programlamasını bir esinti yapar. Bir düğmeye şunu söyleyebilirsiniz: "Lütfen, bu nesneyi bastığınız zaman bu nesne için çağırın", ve düğme bunu yapar. İstediğiniz geri arama için herhangi bir yöntem adı kullanmakta özgürsünüz, kütüphane kodunda donmamış, çalışması için bir adaptörden miras almanız gerekmiyor, ne de derleyici aramayı derleme zamanında çözmek istemiyor. ve aynı derecede önemli, iki düğmeye aynı nesnenin iki farklı yöntemini çağırmasını söyleyebilirsiniz.

Henüz başka bir dilde bir geri arama tanımlamanın benzer şekilde esnek bir yolunu görmedim (yine de onları duymak isterdim!). C ++ 'a en yakın eşdeğer muhtemelen muhtemelen gerekli çağrıyı yapan ve yine kütüphane kodunu bir şablon olarak kısıtlayan bir lambda fonksiyonundan geçiyor.

Bu, bir dilin her türlü nesneyi / işlevi / her ne kadar önemli bir kavram-dil-özgürce çevreleyen bir dilde serbestçe geçirebileceğini, aynı zamanda onları biriktirme gücüyle değerlendirebilmeyi öğretti . değişkenler. Herhangi bir kavram türünü tanımlayan, ancak mevcut tüm değişken türlerinde onu (ya da referansını) saklamak için bir araç sağlamayan herhangi bir nokta, önemli bir tökezleme bloğu ve muhtemelen çok çirkin bir kaynaktır. çoğaltılmış kod Ne yazık ki, barok programlama dilleri bu noktalardan bazılarını sergileme eğilimindedir:

  • C ++ 'da VLA türünü yazamazsınız ya da göstergeyi saklayamazsınız. Bu, (C99'dan beri C'de mevcut olan) dinamik boyuttaki gerçek çok boyutlu dizileri etkili bir şekilde yasaklar.

  • C ++ 'da bir lambda türünü yazamazsınız. Bunu bile tanımlayamıyorsun. Bu nedenle, bir lambdayı geçmenin ya da bir referansı bir nesnede saklamanın bir yolu yoktur. Lambda işlevleri yalnızca şablonlara iletilebilir.

  • Fortran'da, bir namelist türünü yazamazsınız. Herhangi bir rutine bir listeden geçmek için hiçbir yol yoktur. Dolayısıyla, iki farklı adelistin üstesinden gelebilecek karmaşık bir algoritmaya sahipseniz, şansınız kalmaz. Algoritmayı sadece bir kez yazamaz ve ilgili isim listelerine iletemezsiniz.

Bunlar sadece birkaç örnek, ama ortak noktayı görüyorsunuz: İlk defa böyle bir kısıtlama gördüğünüzde, genellikle umursamazsınız çünkü yasaklanan şeyi yapmak çok çılgınca bir fikir gibi görünüyor. Ancak, bu dilde bazı ciddi programlama yaptığınızda, sonunda bu kesin kısıtlamanın gerçek bir sıkıntı haline geldiği noktaya gelirsiniz.


1
I have not seen a similarly flexible way to define a callback in any other language yet (though I'd be very interested to hear about them!) Az önce tanımladığınız şey, olay odaklı UI kodunun Delphi'de çalışma şekli gibi. (Delphi'den ağır şekilde etkilenen .NET WinForms'da.)
Mason Wheeler

2
"C ++ 'da bir VLA türünü yazamazsınız" [...] - C ++' da, C99 tarzı VLA'lar gereksizdir, çünkü biz varız std::vector. Yığın tahsisi kullanılmamasından dolayı biraz daha az verimli olsa da, işlevsel olarak bir VLA'ya göre izomorfiktir, bu yüzden gerçekten bir "blub" tipi sorun olarak sayılmaz: C ++ programcıları nasıl çalıştığını görebilir ve sadece "ah evet" diyebilirler. , C, C ++ "dan daha verimli yapar.
Jules

2
"C ++ 'da bir lambda türünü yazamazsınız. Bunu yazarak bile tanımlayamazsınız. Bu nedenle, bir lambdayı geçmenin veya bir nesneye bir referansı bir nesnede saklamanın yolu yoktur" - bunun std::functioniçin.
Jules

3
"Geri arama tanımlamayı başka bir dilde benzer şekilde esnek bir yolla görmedim (onlar hakkında çok şey duymak isterdim!)." - Java'da yazabilir object::methodve bir örneğe dönüştürülür hangi kodun ne olursa olsun alıcı kod bekler. C # delegelerine sahiptir. Her nesne işlevsel dil bu özelliğe sahiptir, çünkü temelde iki paradigmanın kesitinin noktasıdır.
Jules

@Jules Argümanlarınız tam olarak Blub-Paradox'un ne hakkında olduğu: Yetkin bir C ++ programcısı olarak, bunları sınırlamalar olarak görmüyorsunuz. Ancak, bunlar sınırlıdır ve C99 gibi diğer diller bu belirli noktalarda daha güçlüdür. Son noktaya kadar: Birçok dilde mümkün olan geçici çözümler vardır, ancak herhangi bir yöntemin adını başka bir sınıfa geçirmenize ve bunu sizin de sağladığınız bazı nesnelerde çağırmasına izin veren birini tanımıyorum.
cmaster
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.