K tomuto nesmyslnému závěru jste došel jak?
V C/C++ se míchají nesmyslně dvě věci, tj. datový typ a jeho binární reprezentace. Ada má ipso facto jen dva celočíselné typy: aritmetický a modulární. Více není potřeba, protože toto určuje všechny operace nad nimi.
C/C++ má pouze jeden celočíselný typ: modulární (z hlediska terminologie Ady). Protože ovšem není schopno C/C++ určit rozsah datového typu, nesmyslně je zmnožuje do myriád názvů, které jsou ovšem stále modulárním celočíselným typem, ovšem s různými rozsahy hodnot: short/int/long/long long, atd. V Adě nic takového není třeba, protože rozsah si určítě explicitně pomocí zadání rozsahu hodnot čísel typu.
Tedy Ada nahradí všechny C/C++ celočíselné typy jediným typem zvaným modulo celočíselné typy. Příklad:
type Byte is mod 256; -- celočíselný integer s rozsahem 1 bajt
Co autor článku bohužel nevysvětlil je že Integer typ v Adě se nechová jako v C/C++. Je to skutečně pravý matematický celočíselný typ. Při podtečení/přetečení se nepřetáří bitíky, takže 255+1 není -1 na 8bitovém typu, atd.
Tedy typ Integer v Adě je celočíselný typ s tak pěkným chováním, v jakém se v jazycích C/C++ vůbec nevyskytuje. Takový typ v C/C++ neexistuje. V C/C++ existují pouze celočíselné typy, které Ada nazývá modulo typy. Skutečný aritmeticý celočíselný typ, který se více chová matematicky, než počítačově, jazyky C/C++ vůbec nemají.
Tedy rozsah celočíselného typu, který jste měl na mysli, není na libovůli kompilátoru, ale na libovůli programátora. Protože máte k dispozici možnost rozsahu, takže třeba 32bitový znaménkový celočíselný typ (z hlediska rozsahu) v Adě programátor předepíše jako Integer range -2**31 .. 2**31-1, a je to. Zde žádná libovůle kompilátoru není.
Ada je čistější jazyk, a odděluje datový typ a jeho rozsah do dvou samostatných věcí, které si můžete samostatně určovat. Takovou kontrolu celočíselných a jiných typů v C/C++ nenajdete, a proto není vůbec potřeba, aby typ měl určen rozsah, ten si přeci programátor explicitně určí dle své potřeby.
To, že C/C++ naučil několik generací programátorů, že prasecké datové typy jsou normální, je bohužel smutná skutečnost.
P.S.: Autor tohoto příspěvku píše v C++ několik desetiletí, a má C++ opravdu rád. Přesto datové typy v C++ jsou tou negativní stránkou C++ jazyka. Velmi negativní.
Ing. Miloslav Ponkrác
A tyto typy normální Adista by nejspíše nikdy přímo nepoužil.
Autor, který píše tento seriál je důkazem, že někteří lidé umějí programovat pouze v jednom programovacím jazyce, a v něm programují, ať už se jim pod ruku dostane jakýkoli jazyk.
Nechci autora článku shazovat, ale stjeně tak jako „každý opravdový programátor programuje ve Fortranu v jakémkoli jazyce“, autor tohoto seriálu „programuje v C v jakémkoli jazyce“.
Styl těchto článků se mi zdá poněkud nešťastný, a mám pocit, že poněkud Céčkoidní. Jenže v Adě, která je od C velmi vzdálena, je to poněkud jako pěst na oko. Autor namísto předvedení skutečné Ady neukazuje nic jiného, než jak přepsat Céčkové konstrukce do Ady.
Ještě bych přidal problematiku floating point typů - s těmi spousta lidí strašně "kouzlí", takže mnoho algoritmů je zcela špatně nebo "pouze" počítá s obrovskými chybami, protože pro FP hodnoty spousta předpokladů prostě neplatí, například asociativita, distributivita atd.
A není to jen problém C/C++, protože ten typový systém přešel i do Javy (například).
V tomto má Ada skutečně výhodu, protože minimálně programátora donutí se zamyslet, *jaké* hodnoty používá a k jakým operacím s nimi bude docházet.
Typový systém C/C++ bohužel přešel do celé řady dalších jazyků. V zásadě to není primárně made by C, ale je to nešťastný systém. Bohužel po C/C++ ho převzala obrovská spousta jazyků, jako Java, C#, atd.
C-like typy jsou typy, které v podstatě vidí proměnné jako konkrétně strojově uložené bitíky.
Ada-like typy vycházejí z toho, že typy jsou data s nějakými operacemi, a strojová podoba vás nezajímá. Teprve pokud moc a moc chcete, Ada vám umožní kontrolovat i strojovou podobu, ale je to kontraproduktivní.
Adě řeknete s jakými daty chcete pracovat, a zbytek je práce Ady. Zatímco v C/C++ programátor maká za kompilátor, a stejně od C/C++ standardu, ani od samotného C/C++ jazyka nedostává potřebné standardy rozsahů typů ani pomoc v syntaxi.
Adě řeknete, jaká data chce mít, jaké hodnoty v nich chcete mít, případně jaké další podmínky/constrainty (třeba vyjádřené matematickou rovnicí) musí hodnoty datového typu splňovat. A zbytek je na Adě. Je to velice pěkně vymyšlené, a představení těchto věcí ukáže skutečnou krásu a možnosti Ady. Velká škoda, že jen minimum jazyků to od Ady převzalo, ale taková konzistence dat, jakou kompilátor je schopen zajistit v Adě (přesněji pomoci zajistit) se jinde nevidí.
U floating point (Ada má také fixed point reálná čísla v jazyce) většina lidí v C/C++ nejenomže nezná obory hodnot, ani chování reálných čísel ve formátu ieee754 a spol., ale také nekontroluje přetečení (to spadne do ±nekonečna), ani definiční obory funkcí (to spadne do NaN). Neřku-li, že by počítali se zaokrouhlovacími chybami.
Zkrátka datový typ v Adě je dán operacemi a množinami hodnot, nikoli strojovou reprezentací jako v C/C++. Překlad do strojáku je věcí kompilátoru Ady, stejně jako volba nejlepšího strojákového typu. Jako člověk, který C/C++ intenzivně používá před tři desetiletí musím říci, že programátor za C/C++ dělá příliš mnoho věcí místo kompilátoru, že C/C++ je spíše jen fikanější assembler, než vysokoúrovňový programovací jazyk. Přitom Ada nedělá méně optimální kód, než C/C++.
To není smělé tvrzení, ačkoli benchmarky nemám, a nejsou ani třeba.
Benchmarky stejně nedělají nic jiného, než srovnávají rychlosti kompilátorů, nikoli možností jazyka.
Kód a Ady může být dokonce udělat i rychlejší kód, neboť má více informací, než je v kódu C/C++. Nejvíce to bude patrné v multithreadových aplikacích, protože v Adě to řeší jazyk, ve většině jiných jazyků to řeší knihovny. A Ada má možnost vyhazovat různé zámky a optimalizovat zamykání i počet threadů, protože jazyk o všech paralelních akcích doknale ví, řeší to jazyk, nikoli knihovny, a Ada také celou paralelní práci i se zamykáním a synchronizací optimalizuje jako celek.
Ostatně dříve se kernely operačních systémů psaly třeba v Module, Adě i jiných jazycích, myslíte, že Céčko je nějak lepší nebo rychlejší? Proč by mělo být.
Ten mýtus, že C/C++ je nějak rychlé, nechápu. V porovnání s Javou, C#, Perlem, Ruby, Pythonem ano. Ale každý slušný optimalizovaný jazyk dokáže to samé co C.
Ada navíc umožňuje lépe zvolit strojové reprezentace proměnných, protože to je věcí kompilátoru, nikoli programátora.
Ostatně NASA nasazuje Adu i do pomalých procesorů, proč asi?
Ada je jazyk schopný velmi dobré optimalizace.
Rychlost výsledné binárky je dána více množství informací ve zdrojovém kódu, spíše než jeho nízkoúrovňovostí.
Podle mě je spíše smělé tvrzení, že C je nejrycheljší jazyk. Dříve, když se považovalo za běžné jazyky dobře navrhovat, kdy programátoři museli mít teoretické znalosti atd. – by nikdo Céčko za jediný rychlý jazyk nepovažoval.
Rychlost C nad všechny jiné jazyky je spíše urband legend a unixový fanatismus, než pravda.
Já netvrdím, že C je *nutně* nejrychlejší jazyk na světě, ale jelikož je to v zásadě o trošku vyšší assembler, což jste myslím sám psal, bral bych jeho potenciál k napsání nejrychlejšího kódu (po assembleru samotném) jako nulovou hypotézu. Jednoduše proto, že do takového programu je možné všechny ty informace dostupné jazykům typu Ada vložit také.
Rozumím tomu a doufám v to, že kompilátory vyšších jazyků jsou v principu schopny dostat se nad úroveň dobrého optimalizátora v C, ale to je teorie a tu praxi, tj. současný stav toho kterého kompilátoru, nelze prokázat jinak než empiricky.
Ano, v assembleru se dá napsat nejrychlejší kód, ale je to zatraceně těžké. Stejně tak se dá v C napsat zatraceně rychlý kód, ale optimalizátor s tím moc nepomůže. Vzhledem k tomu, co všechno C dovoluje, se musí optimalizátor hodně hlídat (např. aliasing).
Nejdůležitější ale není jazyk, ale návrh datových struktur a algoritmů (i podle architektury). Samotný jazyk je až druhořadý. Pak tady na rootu vznikají humorné diskuze, kde si pár trotlů poměřuje, kdo ho má rychlejšího na naivním O(N^3) maticovém násobení a je na nich vidět, že se znalostma o procesorech skončili někde u 386 nebo podobného starého střepu.
Nejvíc prasáren se stejně omlouvá rychlostí kódu a to i u těch 80% programu, kde je rychlost totálně nepodstatná.
Však já nejsem velkým příznivcem C a ani C++. Když ale někdo napíše, že nějaký překladač produkuje rychlejší kód než jaký se dá běžně napsat v C, zajímalo by mě, jak to ví. Že algoritmus je (často, ne vždy) rozhodující, o tom se nepřu. Že je lepší udržovatelný kód o pár procent pomalejší, o tom se taky nepřu.
Že může Ada (nebo Fortran nebo klidně JavaScript) být někdy a v něčem rychlejší, se taky nepřu. Ale zajímá mě kdy a o kolik. To bez benchmarku nelze zodpovědět.
No, jestli Ada kontroluje u každýho výpočtu přetečení, tak to zrovna rychlý nebude. Jestli se použije nějakej modulo type, kterej zrovna odpovídá nějakýmu nativnímu CPU typu, pak to bude stejný IMHO. Jinak nevěřím, že nějaká konkrétní firma měla tolik prostředků, aby dokázala napsat kompilátor, kterej by konkuroval dnešním nejrozšířenějším kompilátorům. Vono oprimalizovat pro moderní CPU je takový voodoo :-)
BTW kdysi jsem porovnával rychlost u nějakejch intenzivních výpočtů mezi MSVC++ a Delphi - na jaký časy se dostaneme já a kamarád zažranej Delphista u floating point a fixed point obojí 32 bitů a dopadlo ro pro Delphi dost žalostně. I po kouknutí do asm co to Delphi vyprodukovalo jsme kroutili hlavama. IMHO neměl Borland dost síly a prostředků napsat skutečně optimalizující kompilátor.
Oni to ani nechteli, protoze konkurence pro Delphi byl VB, takze ukol znel jasne:
1) co nejrychlejsi kompilace, idealne, aby se to spustilo stejne rychle jako tokenizovany kod
2) vysledne programy musi byt rychlejsi nez analogie ve VB
Takze takto nizko polozena latka byla splnena (a ano - Delphi jsem mel hodne rad, takovy C++ Builder byl vzdycky o dost pozadu, bylo videt kam Borland predevsim smeruje)
Ještě jedna věc, podívejte se také na Fortran a zkuste s ním porovnat rychlost C/C++ pro nějaký matematický výpočet. A opět zjistíte, že C/C++ je rychlostně pozadu.
C/C++ prostě zjednodušením svého jazyka ztratilo také možnosti řady optimalizací.
C/C++ není rychlostně nijak výjimečný mezi kompilátory. Nechápu tu legendu o jeho maximální rychlosti mezi jazyky.
„...C/C++ je spíše jen fikanější assembler, než vysokoúrovňový programovací jazyk.“
Jinými slovy:
C je pouze chytřejší a portovatelnější assembler, nic jiného se od něj nečeká (a kdo čeká, spálí se).
C++ vzhledem k tomu, jak nízkoúrovňové věci v něm musí programátor hlídat a řešit, není možno považovat za vysokoúrovňový jazyk.
Adovské typy jsou nekorunovaným králem Ady. Je to jedno z nejlepších řešení typů, jaké kdy u programovacích jazyků najdete.
Škoda, že autor článku nevyužil možnosti datové typy Ady opravdu představit, stejně tak jako vysvětlit jejich rozdíly oproti C/C++.
Najdete jen minimum programovacích jazyků, kde jsou datové typy tak perfektně povedené, jako je to v Adě. Datové typy jsou v Adě promyšlené, jako nikde jinde. To je jedna z mála věcí, které uzná o Adě i její nepřítel.
V té staré dobré, skoro se mi chce říci lepší, době se dělaly věci kvalitně a důkladně.
V těch dobách mimochodem vycházela spousta vědeckých i matematických prací o teoriích kompilátorů i datových typů. Jako vedlejší efekty vzniklo třeba SQL a relační databáze (také jako důsledek pár článků), nebo regulární výrazy, apod.
Věci byly podložené přemýšlením i odborností.
Pak vznikl nabastlený jazyk C a od té doby je to v háji. Najednou programátor dělá za kompilátor věci, které má řešit kompilátor a jazyk. Jako například abstraktní datové struktury nebo paralelní programování, a celou strojovou reprezentaci dat a podprogramů.
Vzorem programátorů se staly jazyky, které měly polidšťoval assembler (C, C++), a nikoli skutečně vyšší programovací jazyky. V mainstreamu se pak šíří jazyky, které například nedokáží ani pracovat se stringem aniž by programátora obtěžoval strojovou podobou stringu (PHP, Ruby, …).
Zkrátka tehdy programovací jazyky něco uměly. A Ada byl jednoduše dobře a důkladně navržený programovací jazyk, tak se jeho technologie přebíraly jako vzor.
Za programovacími jazyky stály matematici a odborníci.
Dnes se mainstreamové jazyky pokoušejí vylepšovat C, a je jedno, jestli se to jmenuje C++, Java, C#, JavaScript, ObjectiveC, PHP, Perl, Go, Dart, a tisíce dalších prekabátěných a přejmenovaných Céček se špatnými návrhy jazyka jako takového.
Znovu říkám, v C/C++ intenzivně dělám před 30 let, a jsem po internetu známý jako jeho obrovský obhájce. Ale jsou to strojové jazyky určené pro systémové programování, ale pro běžné programování jsou špatně navrženy. Ony i pro to strojové programování dost drhnou, ale budiž.
> JAK by takový dokonalý (nebo lepší "vylepšeného C") jazyk měl vypadat...
Já už jsem svůj pohled naznačil minule, ale myslím si, že by jazyky měly být blíž k teoretickým výpočetním modelům a matematice než k počítači, na němž zrovna běží.
Osobně bych například eliminoval omezený zásobník a tím i chyby přetečení zásboníku, standardem by byla neomezená celá a racionální čísla (modulární aritmetika a floaty dle IEEE 754 by byly přístupné až po explicitním zapnutí nebo vůbec), do proměnných by nešlo přiřazovat a neexistovalo by nic jako referenční rovnost. Přidal bych konstrukce pro paralelní programování jako má například Manticore - viz Programming in Manticore, a Heterogenous Parallel Functional Language.
„Já už jsem svůj pohled naznačil minule, ale myslím si, že by jazyky měly být blíž k teoretickým výpočetním modelům a matematice než k počítači, na němž zrovna běží.“
Kde to mám podepsat?
Pokud člověk chce být blízko procesoru, má strojový kód a assembler. Pokud chce programovat, měl by programovací jazyk být něco jiného, než instancí assembleru, jako jsou C/C++.
suhlasil by som az na malicky fakt, ze je rozdiel medzi idealizmom a realitou. Realita je ta, ze pre programovanie blizko procesora je C dostatocne dobry jazyk. Tj uzivatel tazko oceni krasu jazyka v ktorom je OS naprogramovany ak to bude znamenat ze to bude 2x tak pomale a 4x tak velke. Dnes uz to asi nehra moc rolu (stare zlate casy ked jednoduchy editor nemal 10MB) ale kedysi to bolo ine.
PS : cloveka co by chcel naprogramovat cely OS v assembleri by som celkom rad videl. Skor nez zacne nejaky chytrak tu vytahovat priklady podotykam realny OS.
> A co třeba Rust?
Otázkou je, jak velký negativní vliv bude mít lineární (nebo afinní?) typový systém na modularitu. Další otázkou je, jaké programy půjde zapsat v bezpečném fragmentu jazyka bez ztráty výkonu. Bohužel, Rust momentálně není schopen zabránit memory leakům.
Stačí použít počítání referencí ze standardní knihovny a udělat cyklus. V našem případě zkonstruujeme p
, které ukazuje samo na sebe:
use std::cell::RefCell; use std::rc::Rc; struct Pokus { jiny: RefCell<Option<Rc<Pokus>>>, } impl Drop for Pokus { fn drop(&mut self) { println!("Zaviram"); } } fn main() { let p: Rc<Pokus> = Rc::new(Pokus { jiny: RefCell::new(None) }); let mut jiny = p.jiny.borrow_mut(); *jiny = Some(p.clone()); }
Destruktor Pokus
u se nezavolá a lze ověřit valgrindem, že paměť nebyla uvolněna.
V roce 2013 Rust vypadal trochu jinak - měl vestavěnou podporu pro garbage collector (ukazatele se zavináčem) a uvažovalo se o tom, že by typový systém hlídal, aby nevznikl referenční cyklus - viz [rust-dev] Statically preventing reference-counted cycles while allowing nested rc pointers.
Jsem zvědav, jestli se autor článku rozepíše o Ada trochu hutněji --- zatím se mi zdá, že to může čtenáře ne úplně navnadit. Ada je opravdu dobře navržený jazyk -- a nový standard zavedl spoustu pěkných věcí např. Design-By-Contract explicitně přímo v jádru jazyka. O typech bych psal především -- hodně a hutně -- ostatní je snadno dohledatelné a netřeba čtenáře učit if-else po stopadesáté -- nakonec je Ada imperativní jazyk a moc se v tomto neliší.
http://www.drdobbs.com/architecture-and-design/ada-2012-ada-with-contracts/240150569?pgno=1