> A C++-nál van egy csomó kötöttség, a fordító nem csinálhat jelentősen mást, mint amit a programozó odaírt.
De azt sokféleképpen valósíthatja meg; a valódi kötöttség annyi, hogy a kódnak ugyanazt kell csinálnia, de az nincs megkötve, hogy ugyanúgy.
> Haskellnél meg le se írod a konkrét algoritmust. A fordító olyan algoritmust tesz oda, amilyet akar. Ez a jelentős különbség a kettő között.
Igen, csak az imperatív nyelveknél a kóddal már meg is mondtad, hogy mit szeretnél (a fordító csak a hogyant dönti el), a Haskellnél meg van egy feltételhalmazod, amiből neki nem csak a hogyant, de a mit is ki kell találnia. És ha ebben a "kitalálóban" bug van és rossz algoritmust ír, akkor esélyed sincs kijavítani. Ha meg te írtad fel a feltételrendszert rosszul, akkor nagy öröm lesz debuggolni... Tényleg, lehet-e Haskellnél egyáltalán step-by-step debugot csinálni?
> Itt én inkább arra reflektáltam, hogy maga a C++ fordító milyen jó, betartva az ABI szabályait. Az a különbség, hogy míg egy egyszerű CPU-ra egy jó fordító szinte mindig optimálishoz közeli kódot csinál, addig a bonyolultabb CPU-ra sokszor nem. És ha lenne 6502-re normális C++ fordító, az szinte biztosan az optimálishoz közeli kódot tudna csinálni szinte minden esetben.
Én értem, de én meg pont ezt magyarázom, hogy hiába fog jobb kódot kiadni a fordító egy egyszerűbb CPU-ra, mint egy bonyolultabbra, itt mindenképpen az ember van előnyben, mert ő szűkebb, gyorsabb kódot is tud írni, nincsenek azok a belső megkötések, mint a fordítónál. Meg lehet nézni, hogy ha megírod C-ben, hogy mondjuk nullázza ki a 4-es lapot, akkor az mekkora és milyen gyors kódot fog eredményezni és utána mennyiből tudod ugyanezt megvalósítani tiszta 6502 ASM-ben.
> Nyilván. Ezért ehhez külön érteni kell. Aki ebben dolgozik, annak mint mondtam, nem egy olyan nagy kaland ezeket a dolgokat fejben tartani. Ha egyszer felvetted a fonalat, utána egy újabb CPU-nál "csak" a különbségeket kell megtanulni.
Lehet, csak kérdés, hogy nyersz-e annyit rajta, a megfelelően megírt algoritmusra a megfelelő optimalizációs paraméterekkel rászabadított fordítóhoz képest, hogy megérje-e szórakozni vele.
> Sajnos nem. Nézz meg egyszer egy lefordított kódot. Szinte mindenhol fogsz találni részeket, amiken lehet javítani. Legalábbis nekem ez a tapasztalatom, bármikor ránéztem egy fordított kódra, mindenhol találtam nem optimális részeket. Néha még a legegyszerűbb dolgokat is rosszul fordítja le a fordító,
Elhiszem. De éppen ezért van ötvenezer féle forgatásra vonatkozó kapcsolója a compilereknek, hogy megtaláld az optimálisat. Meg hát kódot írni akkor is tudni kell, ha a fordító jól optimalizál. Rossz algoritmust nem lehet jól optimalizálni.
> Persze, C++-ban sokkal gyorsabban lehet haladni, ez nem vitás. Én csak azzal az állításoddal nem értek egyet, hogy "a CLang vagy a GCC simán jobb kódot fordít annál, amit kézzel írnál.". Nekem az a tapasztalatom, hogy bármikor, mikor szükséges volt gyors kódot írni, mindig tudtam javítani a fordított kódon. Ráadásul úgy, hogy én se vagyok tisztában a mostani CPU-k minden apró részletével. Elég pár CPU specifikus dolgot tudni ahhoz, hogy javítani tudjak a fordítók által generált kódon.
De most akkor azt az egész algoritmust nulláról újraírtad assemblyben a leforgatott kódban, vagy csak belejavítottál? Mert az utóbbi esetben még mindig a fordító generálta a kódot, te csak javítottál rajta és spóroltál pár (vagy akár sok) órajelet.
> Nu mind1, úgy látom nagyjából egyetértünk egy csomó mindenben, csak a fordítókat látjuk kicsit másképpen.
Meg a goto kérdését. Szerintem nonszensz, hogy evil lenne. Ez egy eszköz; csak a használója lehet gonosz, vagy hülye, az eszköz nem. Egyébként ha te kézzel tolod assemblyben, akkor nem is értem, hogy mi bajod vele, hiszen ASM-ben csak goto, meg gosub van. (Illetve jmp, jsr/call, meg a különféle branch-ek, de érted mire akarok kilyukadni.)
Update: Közben látom lent, hogy nem úgy értetted, hát nem jött át; formában vagyok ma. :/
> Csak hogy egy példát is írjak: pár éve csináltam egy tömörítőt, aminek egy része az volt, hogy egy 6x-osan interleave-elt huffman streamet kellett kitömörítenie (azaz egy adatblokkban volt egymás után 6 huffman stream, amiknek a kimenetét kellett interleave-elni). Ez alapból olyan 150MB/sec-kel működött. Miután leoptimalizáltam (az algoritmus nem változott!), lett belőle 1.5GB/sec. És közben volt olyan is, hogy egy apró módosítás 2.5x lassabb kódot eredményezett. Szóval össze-vissza változott az, hogy az adott kód milyen sebességgel fut. Szóval ennyit arról, hogy mennyire optimális kódot csinálnak a mai fordítók... Sok ilyen példát tudnék hozni, bár ennyire durva különbség ritkán van, azt elismerem. De 2x szorzó simán szokott lenni.
Érdekes. Jó volna a kódot is látni, meg a fordítási opciókat, meg az azokra adott assemblyt. Persze nem vitatom, hogy néha eléggé hulladék a végeredmény, amit ki tudnak dobni magukból a fordítók, de elég sok múlik a "bemeneten", meg a különféle beállításokon.
Nekem ennél jobb tapasztalataim vannak a C fordítókkal, amikor a PNG => IFF konverteremet írtam, akkor az volt a cél, hogy Amigán is le tudjam épeszű módon futtatni. Először úgy voltam vele, hogy ha megvagyok a C forrással a többi platformra, akkor majd Amigán a kritikus részeket (Wu kvantizálás, Lánczos újramintavételezés, stb.) átírom 68000-es és 68020-as assemblyre. De a SAS/C tűrhető sebességet produkált így is, így az átírás elmaradt, pedig 68000-esben elég sokat ügyködtem, biztos bírtam volna valamennyit javítani rajta. (Persze, ha valaki 7.14 MHz-en akar egy 1920x1200-as, 64-bites színmélységű PNG-t átkonvertálni, akkor az nem két perc lesz, de megcsinálja.)