No neviem, ale ja osobne radšej používam C/C++ než Javu, C#, a iné podobné jazyky... môj list jazykov je:
1. JavaScript
2/3. C/C++
2/3. Golang
(stále sa neviem rozhodnúť medzi nimi v poradí v rebríčku)
4. Python
5. Raku
6. ERLang
.
.
.
X. ostatné jazyky
a tiež sa mi nepáči jak to C/C++ začína ísť do kytek.
25. 5. 2020, 19:10 editováno autorem komentáře
[Josef Ink]
"Celá ta myšlenka přetěžování aritmetického operátoru pro účely zápisu/čtení ze streamu je nějaká divná."
To je dle meho nazoru ciste vec pohledu. Ja se na operatory << a >> v pripade std::iostream nedivam jako na aritmeticke operatory, ale vnimam je jako (v prenesenem slova smyslu ) smerove operatory - ukazuje odkud kam tecou data. Stream = proud. Proud dat, odnekud - nekam. Obdobne jako napr. v shellu operatory presmerovani.
Ale urcite by se nasly i pripady kdy mohou pusobit neprakticky, nebo tezkopadne, to nepopiram. Ale myslim, ze zrovna v C++ Ti nekdo nebrani jit jinou cestou, jen si ji proste musis vydlazdit (napriklad si na to napsat vlastni funkce/metody, ktere vic vyhovuji tvym pozadavkum - pokud uz to neudelal nekdo pred tebou).
" A je to i dost nepraktické - zde uváděné moduly format a fmt jsou o dost lepší způsob, jak někam vyplivnout řetězce, nemyslíš?"
Co se tyce std::format, jednak byl pridana teprve nedavno v C++20, jednak stejne vysledek musis poslat pres std::cout na terminal a jednak ani nevidim duvod proc to zrovna v tomto pripade pouzit, leda ze bych chtel do kodu cpat funkcionalitu, ktera stejne nebude mit na vysledek zadny vliv. Ja vim, ze to je dneska strane cool, ale to me nezajima.
26. 5. 2020, 23:49 editováno autorem komentáře
To mi zní jako ex-post racionalizace. Mě ta myšlenka připadá od základu špatná. Příklad: potřebuji do výstupu dát nějakou hodnotu posunutou o pár bitů. Když napíšu
cout << k << 2
tak výsledek nebude zrovna to, co očekávám. Když místo toho napíšu
cout << (k << 2)
tak to bude najednou správně... jenže závorky, které normálně u oprerátoru znamenají pouhou změnu priority vyhodnocování, tady najednou zcela změní význam celého výrazu a to jenom proto, že cout náhodou předefinoval << aniž by to bylo aspoň jasně vyjádřené v typovým systému. To je jenom jeden z mnoha příkladů, kdy je C++ vnitřně nekoherentní.
Celé iostreamy jsou jedna z nejstarších a asi i nejhůř navržených částí standardní knihovny. :(
Operátor << má pro účely formátování dost nevhodnou prioritu. Je třeba nad andy a ory.
Není tam moc prostor pro nějaké parametry, takže se tam cpou stavově přes mamipulátory. Z toho pak plynou brikule s ukládáním a obnovováním stavu streamu. Psal jsem nějaké složitější formátování přes iostreamy a znova bych do toho už nešel. Strčit tam hotový buffer a konec.
A pak je tam taky slavný std::endl, který obsahuje std::flush. Vyprázdnění bufferů není úplně rychlé. I když třeba při výpisech na windowsech se to moc nepozná.
Roste tlak na cenu, to je celé. Dnes existují dobré jazyky s vyšším množstvím dokončené práce za jednotku času, tak se přirozeně dostávají do popředí tam, kde to je možné. GUI aplikace, kde se iteruje velkou rychlostí, kde se požadavky mění několikrát do roka, kde chyba nemá závažné důsledky (prostě se to v příští verzi opraví)... tam je na dnešní dobu jazyk jako C moc drahý.
V mém oboru (embedded)... je C pořád #1, a ještě velmi dlouho bude. Je to lehká abstrakce nad dnešními procesory, proto je to ideální jazyk k vývoji kernelů operačních systémů, firmwaru a dalších programů, které mají blízko k železu.
Chyby stojí peníze (reputaci) jen když koncový uživatel není pasivní a tolerantní ovce. A to my jsme. Stačí se podívat třeba na současnou Android scénu. Ani nejvyšší cenová není bez ochromujících chyb, a to i hardwarových... ale my si stejně koupíme za rok další. Překvapivě rychle se smíříme s různými obezličkami (třeba že foťák se spouští až napodruhé, že po posledním updatu vydrží baterie jen jeden den, ...) i u zařízení za skoro 30 tisíc, a tak má výrobce zpětnou vazbu maximálně v podobě nějakého rantu někde v diskuzi.
Aplikace pro nekonečně tolerantní ovce se dneska nedělají v C++. Výjimkou jsou hry, kde se C++ používá především proto, že enginy, frameworky a další nástroje už jsou pro C++, a také proto, že začít používat úplně nový jazyk by představovalo riziko, které žádný projektový manažer logicky (a správně) nechce podstoupit v kontextu, kde vývoj produktu stojí obrovské peníze a jeho komerční životnost, během které se musí investice vyplatit, je potenciálně v řádu několika měsíců.
[Cabron]
Ja jsem toho nazoru, ze se stoupajici komplexitou projektu stoupoupa i mira mozne chybovosti daneho projektu. Dokonce bych rekl ze je to davno znamy fakt. Cim bude projekt slozitejsi, tak vic je vam pak nicemu, ze program dokaze dokonala automaticky zpravovat svou pamet, kdyz se tam skryvaji mraky chyb jineho razu, ale protoze v kodu se tezko orientuje, tak se dlouho a tezko odhaluji. No a s tim vice budou na vyznamu pribyvat i jine vlastnosti jazyka jako je rychlost zpracovani, velikost vysledneho kodu, ale i treba takove veci jako citelnost, atd...
26. 5. 2020, 12:17 editováno autorem komentáře
Čistě z nostalgických důvodů, pravá škola bylo psát v céčku NLMka. Stačilo zapomenout uvolnit jen jeden malej kousíček paměti, celej server šel do abendu a několik desítek až stovek naštvaných uživatelů. Žádné "vona ta exception někam nakonec probublá".
Dneska? Člověk jen trochu nastaví ulimit, spustí browser a ten prostě slítne. Tak nevím jestli je tenhle propastný rozdíl jen nostalgický, ale vývoj "aplikace si neporadí když brk() failne -> nesmí failovat -> boha vono to vyžere celou raměť -> objev OOM killeru -> aplikace místo ošetření chyby v alokaci musí znát rovnáky na vohejbáky všech možnejch i nemožnejch systémů aby nebyla killnuta i když nic špatného neprovedla" mi prostě připadá poněkud nešťastný.
Jo, to je fakt super, ze server bez ochrany pameti zbuchne cely kvuli chybe nejake prilinkovane knihovny.
Zrovna na tom novellu to byla prevelika krasa, kdyz se na tom pokouselo prozozovat Apache.
Este lepsi ovsem bylo, kdyz si clovek vyrazil pakl dernych stitku, s tim zasel do datacentra, sjel derne stitky, precetl si chybu a druhy den sel iterovat znova.
[Youda]
Takze to mam chapat, tak ze jedna jedina vlastnost - zde dejme tomu automatizace zpravy pameti - je ten hlavni faktor pro urceni zda je jazyk moderni a pouzitelny? A vsechny ostatni vlastnosti jazyka(/u) jsou naprosto nepodstatne? A napadlo vas, ze to co konkretne Vy povazujete za zastarale, neuzitecne, potencionalne nebezpecne, popripade nehodne tohop aby jste s tim stracel Vas drahoceny cas, nekdo jiny muze povazovat prave za velmi uzitecnou vlastnost, ba mozna je velmi rad, ze spravu pameti ma ve svych rukou?
Historie ukázala, že "mít správu paměti ve svých rukou" je v drtivé většině případů objektivně špatně. Je o tom tato zprávička, jsou toho plný buglisty, katalogy zranitelností, všechny ty další jazyky co se to snaží řešit atd. A bohužel si nemusíme nalhávat, že ani lidi co se můžou považovat za experty a jsou rádi že mají paměť ve svých rukou se nedopouští chyb při správě paměti.
Nerad bych dával příklady ideologií z běžného světa, které se mnohokrát prokázaly jako špatné a přesto to pořád někdo zkouší, ale v IT považuju iluzi o kontrole nad správou paměti za přesně takovou ideologii. Na to jsem už viděl dost expertů, kteří si mysleli že ví co dělají a nebáli se toho využít.
Správu paměti má člověk vždycky ve svých rukou, i s GC. V takovém Rustu, kde GC není, ji má ve svých rukou úplně stejně, jako v C++, akorát, že v C++ může maximálně slibovat, že to je vyřešené správě, kdežto v Rustu se provádí důkaz správnosti - a pokud implementace prokazatelná není, tak to compiler nevezme.
Samozřejmě, že kromě správy paměti je spousta dalších věcí, kvůli kterým C++ považuji za horor. Namátkou: totálně rozbitý a (pochopitelně) neprokazatelný typový systém, kde navíc spousta věcí chybí (algebraické typy...), šablony, které jsou jenom jakási alternativní syntaxe pro #define, kontrola výjimek, při které se výjimky alokují na haldě a používá se copy konstruktor, neboli vyvolání výjimky může samo o sobě vyvolat výjimku atd, zároveň definice výjimek není součástí API dané funkce a může se libovolně a nepředvídatelně měnit, move konstruktor, jehož používání není definované a záleží a libovůli překladače (pokud se nemýlím, dokonce nikde nestojí ani to, že použití move konstruktoru musí být konsistentní alespoň mezi dvěma buildy, respektive může záležet i na volbách překladače), chybí podpora modulů (ta se snad konečně objevila aspoň v C++20 a možná ji za takových dvacet let knihovny dokonce začnou i používat), "pozoruhodná" IO knihovna iostream, kde nějakého génia napadlo, že nejlepší způsob, jak dělat IO, je arbitrárně předefinovat bitshift operátory a kde formátování výstupu (dec, hex atd) je stavový flag a ne typ streamu, takže... atd... atd...
Takže nejen, že C++ považuji za zastaralé a neúčinné, ale k tomu jsem skeptický vůči těm, kteří odmítají připustit, že tyto problémy a milion dalších jsou reálné a že je celkem nic neomlouvá. To neznamená, že nejsou případy, kdy je C++ správná volba z naprosto legitimních důvodů, ale dobře navržený jazyk to v žádném případě nebyl ani na tehdejší dobu, natož vzhledem k dnešním možnostem.
Kdo v C/C++ umí psát opravdu bezpečně? A tím nemyslím jednoduchou aplikaci o 10K řádků, ale něco rozsahu srovnatelného s Chromiem, které má v C+C++ přes 14M řádků, když nepočítám komentáře a prázdné řádky: https://www.openhub.net/p/chrome/analyses/latest/languages_summary
25. 5. 2020, 22:57 editováno autorem komentáře
Zajimava otazka a jestli mohu, zeptam se z jineho uhlu: Existuje vubec jazyk, v nemz lze psat naprosto bezpecne a neprustrelne JAKYKOLIV rozsahly projekt?
Kdyz nad tim uvazuji, asi bych - za sebe - odpovedel, ze to neni vubec otazka jazyka jako takoveho. Podle me jsou tri hlavni faktory ktere to ovlivnuji:
1) Ucel vysledneho produktu
2) Rozsah a komplexnost
3) Navrh
Hodne to zjednodusuji a uvedomuji si, ze o tom se napsalo tuny obsahlych odbornych pojednani, ale myslim, ze pro ilustraci to staci. Napr o mame tu chrome a naproti tomu dejme tomu Kate (vubec netusim jak moc je rozsahly, ale dovolim si do toho zapocitat KDE Libs a Qt a je z toho moloch ja krava). Slysel nekdy nekdo, ze by byla zneuzita nejaka dira v Kate?
Upřímně, netroufám si odhadnout, jsem si vědom argumentů tím i oním směrem, které jdou proti sobě, takže těžko odhadovat co převáží, např.:
- chyb by bylo mnohem více, protože chyby s prací s pamětí mívají typicky mnohem horší následky.
- chyb by bylo mnohem méně, protože většina patlalů to po pár coredumpech vzdá.
Jistě hraje roli spousta věcí a technicky vzato zranitelnost může obsahovat i celkem jednoduchý vzoreček v Excelu.
Nicméně C/C++ má ve srovnání s mnohými jazyky o celou třídu potenciálních zranitelností víc, a podle této zprávičky to není jen teoretický problém.
Ano, MLoC je jen orientační metrika, záleží na spoustě dalších věcí. Budu jako příklad brát i jiné kusy softwaru, které jsou dostatečně rozsáhlé (možná ne nutně jako Chromuim, ale neměl by to být softwarevyvinutelný jako one-man-show) a dostatečně interagují s rizikovým okolím. Myslím, že Kate až tolik neinteraguje s nebezpečným okolím. Analogicky by šlo udělat rozsáhnou aplikaci, která se ale nějak obejde bez dynamické alokace paměti. Tam taky neuděláte use-after-free.
A pokud se bavíme o reálném zneužití zranitelnosti a nejen o její přítomnosti, vstupuje tu do hry i další faktor. Jak moc se aplikace reálně používá s potenciálně nebezpečným vstupem. Prohlížeč běžně. Textový editor teoreticky můžete, ale na vývoj tím můžete otevírat třeba i jen svoje důvěryhodné soubory. Takže třeba https://github.com/vim/vim/commit/d0b5138ba4bccff8a744c99836041ef6322ed39a#commitcomment-19938002 dost možná prošla bez zneužití, ve webovém prohlížeči nebo v serverovém softwaru by podobná chyba mohla vyústit v hromadné útoky. A běžný franta uživatel si pokročilejší editor plaintextu ani nebude instalovat. Software pak může být napsán řádově hůře, a přitom se případné zranitelnosti nebudou až tolik zneužívat. A nejspíš se nebudou ani tolik hledat, takže statistiky objevených zranitelností mohou u podstatně hůře napsaného softwaru vypadat lépe.
Prakticky vzato: Pokud se takovéto programátory nepodařilo sehnat Googlu v dostatečném množství a přes všechna ta opatření završená jejich štědrým Vulnerability Reward Programem*, nedá se moc čekat, že se těmto problémům vyhnu výběrem dobrých programátorů.
*) VRP typicky nebývá to úplně první opatření. Jinak by to byl celkem drahý pronájem různých (i volně dostupných) automatizovaných nástrojů, zvlášť u open-source. Ostatně Google z VRP paušálně vylučuje (nebo aspoň vylučoval) nedávné akvizice.
[Vit Sestak]
Dekuji za reakci, Ja si myslim, ze to vidime oba velice podobne. Az na to, cemu dame ten finalni vyznam, dokonce souhlasim i s Vasim zaverem. Rozdil je jen v tom, ze osobne bych necekal ze pri slozitosti a ucelu Chrome dosahnou o moc lepsich vysledku pouhym pouzitim jineho jazyka v projektu.
Myslenka s Kate je v tom, ze si myslim, ze ona neduvera v C++ je dana hlavne tim, co se v psychologii naziva survivorship Bias (zkresleni prazivsich) V nasem pripade jde o to, ze budeme prirazovat vetsi vyznam projektum, u kterych se chyby nasli a projekty ktere bezi bezproblemove (a ja ale netvrdim, ze tam chyby byt nemohou) vicemene nikoho v tomto hledisku nezajimaji a tak se jevi, ze psani rozsahlych projektu v C++ zakonite vede k chybovosti, nebo rovnou k realne zneuzitelnym zranitelnostem. Protoze ty ostatni jsou ignorovany.
A obavam se ze to neni otazka jen C++, ale v podstate jakehokoliv Jazyka. A taky toho, ktery jazyk mi je sympatictejsi.
Zajimava otazka a jestli mohu, zeptam se z jineho uhlu: Existuje vubec jazyk, v nemz lze psat naprosto bezpecne a neprustrelne JAKYKOLIV rozsahly projekt?
Původní důležitou otázku jste posunul do nesmyslu. Samozřejmě dává smysl používat jazyky, ve kterých lze psát bezpečněji. To, že to stále není naprosto bezpečné a neprůstřelné je sice škoda, ale je to pořád lepší, než psát v jazycích, které jsou k těm chybám náchylnější.
Podle me jsou tri hlavni faktory ktere to ovlivnuji
Můžete mít pět aplikací, které budou mít tyhle tři faktory stejné, ale každá aplikace bude napsaná v jiném jazyce. Dává smysl jazyky porovnávat podle toho, která aplikace bude nejbezpečnější. Stejně jako dává smysl je porovnávat podle toho, která bude nejrychleji napsaná, která nejsnáze udržovatelná, která bude mít nejmenší nároky na hardware tak, aby měla použitelnou odezvu.
Slysel nekdy nekdo, ze by byla zneuzita nejaka dira v Kate?
To ovšem vůbec nevypovídá o tom, zda tam bezpečnostní chyby jsou nebo nejsou. Může to vypovídat jenom o tom, jaká je příležitost je zneužít. Také jsem nikdy neslyšel o tom, že by někdo vyloupil vlakové nádraží, zatímco vyloupení banky je oproti tomu častý jev. Ale vůbec to neznamená, že jsou nádraží lépe zabezpečená, než banky.
[Filip Jirsak]
"Původní důležitou otázku jste posunul do nesmyslu. Samozřejmě dává smysl používat jazyky, ve kterých lze psát bezpečněji. To, že to stále není naprosto bezpečné a neprůstřelné je sice škoda, ale je to pořád lepší, než psát v jazycích, které jsou k těm chybám náchylnější."
Obavam se, ze ja jsem v teto chvili vubec predrecnika neptal na to co dava smysl ci ne. Ja jsem se ptal, zda existuje realne jazyk, v nemz se daji bezpecne a bezchybne psat velke komplexni projekty. O smyslu tam v tuto chvili nebylo ani slovo.
D.A. Tiger: Zase stejná chyba, nesmyslně požadujete, aby něco bylo stoprocentní.
Odpověď na vaši otázku, zda existuje jazyk, v nemz se daji bezpecne a bezchybne psat velke komplexni projekty, je jednoduchá – neexistuje (a nikdy existovat nebude). Akorát že z té odpovědi vůbec nic neplyne, je naprosto nezajímavá.
[Filip Jirsak]
"Zase stejná chyba, nesmyslně požadujete, aby něco bylo stoprocentní."
Rad bych Vas pozadal, aby jste mi prestal podsouvat co si myslim, nebo co ocekavam.
"Odpověď na vaši otázku, zda existuje jazyk, v nemz se daji bezpecne a bezchybne psat velke komplexni projekty, je jednoduchá – neexistuje (a nikdy existovat nebude). ]"
Zajmavy paradox - ja si to totiz myslim take, hned na zacatku jsem o tom psal. Jenze Vy mi to musite za kazdou cenu vyvratit.
"Akorát že z té odpovědi vůbec nic neplyne"
Ale ano. Minimalne to, ze nelze totez pozadovat ani po C++
"je naprosto nezajímavá."
Tak proc se k ni vyjadrujete? O.o Ta puvodni otazka ani nebyla smerovana na Vas.
26. 5. 2020, 15:31 editováno autorem komentáře
ps. Respektive, abych byl uplne presny v tom co jsem psal, jsem presvedcen o tom, ze bezpecnost a spolehlivost vysledneho projektu, nezalezi ani tolik na jazyku, jako na tom, jak se k nemu postavy programatori a k cemu je urcen.
Coz je zaver vychazejici mimo jine z toho o cem jsem psal vyse...
26. 5. 2020, 15:37 editováno autorem komentáře
Rad bych Vas pozadal, aby jste mi prestal podsouvat co si myslim, nebo co ocekavam.
Já vám nic nepodsouvám.
Minimalne to, ze nelze totez pozadovat ani po C++
Jenže on to po C++ nikdo nechce.
Respektive, abych byl uplne presny v tom co jsem psal, jsem presvedcen o tom, ze bezpecnost a spolehlivost vysledneho projektu, nezalezi ani tolik na jazyku, jako na tom, jak se k nemu postavy programatori a u k cemu je urcen.
No, a jsme zpět u toho. Právě proto jsem na to reagoval. To, že neexistuje žádný 100% bezpečný jazyk, neznamená, že bezpečnost na jazyku nezáleží. Bezpečnost na jazyku záleží – pokud má automatickou správu paměti, nemohou tam být chyby plynoucí ze špatné správy paměti; pokud je staticky typovaný, odpadají chyby plynoucí ze špatné práci s typy. A tak dále. A ještě než v tom zase začnete hledat stoprocentní spolehlivost – i jazyky s automatickou správou paměti často umožňují nějakou část paměti spravovat ručně, i staticky typované jazyky umožňují kontrolu typů přebít. V takových částech pak samozřejmě k uvedeným chybám může docházet.
Hlavně existují jazyky, kde se spousta věcí řeší daleko méně ceremoniálně. Nejsem žádný velký programátor, ale něco málo C, Javy, Pythonu apod. jsem viděl v různých kontextech.
Od nějaké velikosti projektu stejně už nikdo neví, co se skutečně děje a jaké instrukce se procesoru pošlou (natož v jakém pořadí se potom skutečně vykonají, a po zkušenosti Meltdown apod. se zdá, že to relevantní je). Je tedy příležitost zvolit vyšší, robustní a hlavně konzistentní abstrakce a nechat vnitřnosti nějakému chytrému AOT/ JIT kompileru. V poslední době se zabývám ve volných chvílích Clojure a Clojurescriptem, protože mám možnost nahlédnout do projektu (https://orgpad.com/about), který je napsaný výhradně v této kombinaci. Kdybych viděl Clojure před Javou, tak se Javou nebudu zabývat, protože prakticky všechno, co umí Java umí Clojure taky a velmi často stručněji, konzistentněji a s poměrně malou námahou se dá leccos sdílet mezi Clojure a Clojurescriptem - takže Client a Server můžou sdílet dost kódu. Ano, na pár věcí se hodí vědět, jak to JVM a jiné VM nad kterými nějaký dialekt Clojure beží implementují, třeba když chcete mluvit s nějakou C knihovnou z Clojure. Tam potom koukáte na věci typu JNI, JNR apod. Na většinu běžných úkolů, kdy taháte nějaká data z databáze, máte nějakou logiku a komunikaci Client-Server, tam se s přednostmi Clojure/ Clojurescript kombinace dost špatně drží krok.
GraalVM tohle do velké míry řeší. Viz např. https://github.com/borkdude/babashka když už jsem psal o Clojure. Je tam dost práce, ale určitě to postupně bude další podporovaná možnost.
JIT rozhodně nesmysl není, jenom v poslední době vzniklo více možností a na něco je lepší to a na něco se hodí více něco jiného.
V prohlížečích se nepřechází na AOT, na serverech se nepřechází na čistě kompilované jazyky. Android 5 přešel na AOT, ale v Androidu 7 byla přidána podpora JIT kvůli optimalizacím. JIT neznamená JVM, JIT má třeba i V8, SpiderMonkey nebo Parrot.
GraalVM k JIT přidává i AOT – a pokud chcete vědět, co je budoucnost, tak právě tohle – univerzální VM, pod kterou běží spousta jazyků, která mí JIT i AOT a každý si může vybrat, co potřebuje.
Ona AOT v prohlížečích by asi byla pekelně nepraktická. Jako hlavní nevýhoda JIT se často udává rychlost startu. To je pravda, pokud to srovnáváme s již zkompilovaným kódem. Pokud to srovnáváme s AOT s ještě nezkompilovaným kódem, má zde JIT naopak výhodu. Nemusí kompilovat naspepo všechno. Typicky se zde začíná v interpretu a samotná JIT se ke slovy dostane až později, a to jen v částech, které se ukázaly jako často používané. JIT tak může udělat méně práce než AOT, ale důkladněji a bez potřeby zkompilovat na začátku úplně všechno, což by trvalo.
AOT v GraalVM – to je (aspoň zatím) k dispozici jen pro JVM. Ono není až tak snadné udělat dobré AOT ani pro JVM. U jiných statických jazyků by to možná šlo podobně, ale byl by potřeba udělat frontend, který by umožňoval některé věci konfigurovat. U dynamických jazyků bude AOT ještě náročnější, protože zde nelze aplikovat closed-world-assumption. (Což je IMHO další důvod, proč prohlížeče nemají AOT.) JIT může optimisticky aplikovat CWA a v případě porušení předpokladu může kód překompilovat za běhu. U čistého AOT kód překompilovat nemůžete. A asi nechcete defenzivně zkompilovaný JavaScript, kde bude výsledný kód předpokládat různé edge cases jako změnu prototype za běhu nebo dokonce volání eval, které může změnit nebo dodefinovat i lokální proměnnou*.
(Možnost použít ostatní jazyky v rámci native-image ještě neznamená, že jsou tyto jazyky zkompilovány ještě před spuštěním.)
I já si myslím, že tudy vede cesta a jednoho dne bude stačit napsat interpret a dostaneme nejen JIT, ale s malým úsilím i použitelné AOT. Ještě tam ale nejsme.
* Uvažte třeba kód function foo(x, y){x(y); return z;} a zkuste jej nějak rozumně ručně zkompilovat (klidně do céčka), aby fungovaly různé edge cases, bylo to rozumně ryché, a aby nebylo za žádných okolností překompilovávat. Obecně neznáte ani lokální proměnné. Jak to bude fungovat s voláním foo(eval, "var z = 1")? Nezapomeňte, že ne vždy budete při kompilaci vědět, že předáváte eval.
=====
Pracuju na GraalVM v Oracle Labs. Zde uvedené názory jsou moje vlastní a nemusejí se shodovat s oficiálním stanoviskem Oracle. Příspěvek ani nemusí být ve shodě s plány firmy Oracle.
Já uvidím budoucnost v používání více různých mechanismů podle vhodnosti pro daný účel. Nějaké mixy AOT+JIT smysl dávají, ale ne vždy chceme JIT. Ta typicky znamená také zvýšenou paměťovou náročnost, protože musí být připravena na tzv. deoptimalizace ve chvíli, když zjistí, že neplatí nějaký předpoklad, na kterém staví spekulativní optimalizaci.
Ukládat výsledek JITu zní smysluplně, ale taky to není tak jednoduché. Znamená to někam si ukládat stav. U aplikace sdílené mezi uživateli to může znamenat, že si každý uživatel bude ukládat stav do svého profilu, protože nebudeme chtít dát ostatním uživatelům možnost zapisovat do globálního stavu. Otázkou je taky více instancí jedné aplikace. A v neposlední řadě to může být trochu magie. Různé běhy stejného softwaru mohou mít různé požadavky a v principu to znamená, že rychlost běhu aplikace může být ovlivněná předchozím během – a to i negativně. To mohou způsobit různé deoptimalizace, které se v rámci jednoho běhu budou dít vzácně nebo vůbec, ale napříč běhy se dít mohou. Nevím, jestli z fleku vymyslím úplně realistický příklad, tak aspoň něco ilustračního:
Mějme aplikaci, která pracuje s databází. Díky JDBC bude umět více různých databází. Já budu dlouho pracovat pouze s databázovým driverem X, takže JIT zjistí, že má jedinou implementaci různých JDBC tříd, a bude podle toho optimalizovat (inlinuje volání virtuálních metod apod.). Jednoho dne ale použiju na chvilku juinou databázi s driverem Y. JIT zjistí, že má najednou dvě implementace různých rozhraní k JDBC, tak veškeré optimalizace s tím spojené zahodí, a časem zkompiluje generičtější kód. Ten už nebude až tak rychlý, ale bude univerzálnější. Protože ale budu dál používat jen databázi s driverem X, znamenalo pro mě jedno spuštění s driverem Y trvalé zpomalení aplikace.
Rozhodně tím nechci říkat, že JIT cache nemá budoucnost. Jen naznačuji, že situace není až tak jednoduchá a jednoznačná.
===
Opět, je to jen můj názor, který se nemusí shodovat se stanoviskem mého zaměstnavatele…
Tohle je lichý argument. Možná někomu dělá dobře, že sám sebe ujišťuje, jaký je l33t R3aL Pr0gr4mm3rZ, ale uživateli i zadavateli je to srdečně jedno - a pokud není, měl by se snažit dospět nebo případně se obrátit na psychiatra. V praxi je u softwaru důležitých pět věcí (v náhodném pořadí): výkon, cena, bezpečnost, featury, uživatelská přívětivost. Dejme tomu, že přívětivost nezáleží na použitém jazyku (o tom se dá diskutovat, ale budiž). Z hlediska vyvinutých featur za nejnižší cenu nemá C++ šanci proti Pythonu, Go a podobně. Z hlediska výkonu zaostává za C, Fortranem a Rustem. Z hlediska bezpečnosti je důležitá prokazatelnost, ne jenom ujišťování a ego, a v tom je C++ absolutní katastrofa, tady vede Rust, Ada a Haskell. C++ má dosud své nezastupitelné místo díky tomu, že pro něj existuje mnohem víc nástrojů, než pro objektivně lepší jazyky, podporuje víc cílových platforem a mnohem víc lidí s ním umí. To ale neznamená, že by neměl být tlak na jeho postupné opouštění. Tvrzení že "dobrý programátor" dokáže napsat dobrý kód i v C++ je na stejné úrovní, jako že "dobrý řidič" dokáže jet i s autem s prasklými pneumatikami a které nemá brzdy. U mě to spíš vyvolává pocit, že takový "programátor" až tak dobrý není, když ani nedokáže pochopit, jak velká výhoda je, když někdo vyrobí auto, které stojí polovinu a jezdí zadarmo nebo vymyslí nezničitelné pneumatiky.
Což je prakticky one-man show. Na tak malém projektu může být celkem jednoduchá a predikovatelná alokace/dealokace paměti. Oproti prohlížeči, kde máte celkem komplexní webovou stránku ovládanou javascriptem, je to neporovnatelný rozsah. Ostatně si můžete všimnout, že polovina těch chyb s pamětí tvoří use-after-free. To není primitivní implementační chyba jako buffer overflow, to prostě znamená, že někdo někde zapomněl pointer po dealokaci a dál ho používal. Což se v tak rozsáhlé aplikaci (řádově rozsáhlejší než váš bot) hlídá poměrně těžko.
Škoda, že Google nezmiňuje více o té druhé polovině chyb práce s pamětí. Možná v tom budou i jednodušší implementační chyby jako buffer overflow – tipoval bych, že spíše staršího data a nejspíš ne úplně učebnicové případy, které by zachytila statická analýza.
V tom je právě ten problém, každý si myslí, že píše bezpečně a nelze to jinak posoudit než důvěrou v tazatele, to je málo.
Pokud se podívám na tvůj kód, hodně zpozorním, máš tam spousty fixe-sized array, u kterých nekontroluješ přetečení, stačí malá nepozornost a právě problém, o kterém je článek, je na světě.
Tenhle kód při parsování jsonu je zranitelný na buffer overflow, https://github.com/ondra-novak/mmbot/blob/master/src/brokers/httpjson.cpp#L61-L68, možná pro tvoje účely to je OK, u chromium by to byla kardinální chyba.
Poté používáš funkce jako sprintf (https://github.com/ondra-novak/mmbot/blob/master/src/trainer/main.cpp#L884) nebo sscanf (https://github.com/ondra-novak/mmbot/blob/master/src/brokers/isotime.h#L26) bez ošetření buffer overflow. Jasně v tomhle kódu to je třeba teď bezpečné, ale za nějakou dobu tam někdo udělá jinou úpravu a bezpečnostní chyba je na světě (podvrhnout chybný čas aplikaci lze třeba relativně dobře). Tyhle věci musíš automaticky ošetřovat a nespoléhat, že je někdo jiný použije dobře.
Na řádkách L61-L68 buffer overflow není. Data se cpou o ostringstreamu a limitem je maximalne velikost paměti - cpou se po blocich
Použití sprintf a sscanf by se dalo jistě nahradit lepším řešením, ale v daném kontextu ano bylo rychlejší pro implementaci a i troufnu si říct i pro performance.
Se závěrem nesouhlasím. Pokud někdo přebírá kód formou copy&paste - je zodpovědný za jeho obsah, jako by ho napsal sám, svými prsty.
Pokud jej přebírá jako knihovnu, je zodpovědnost na autorovi knihovny. Také je potřeba, aby dotyčný definoval kde se knihovna hodí - stejně jako si koupíte v reálném obchodě zařízení, taky je napsáno, že se nesmí používat tu a tam a že je k úrčitému účelu.
Nespoléhal bych se slepě na překladač s tím, že musí zaručit bezpečnost. Nemusí. Pokud tomu půjde naproti bezva, ale nemusí.
C/C++ může stále mít význam, pokud chci napsat něco pekelně rychlého, ale na bezpečnosti mi nezáleží -- třeba fyzikální simulaci pro interní použití. V takovém případě si člověk rád ušetří dodatečný overhead bezpečnějších jazyků typu Rust, ať už v nárocích na vývojáře (boj s borrow checkerem), tak potenciálně runtime overhead (zrovna u Rustu obecně moc není, ale třeba u jazyků postavených na VM).
Jazyk je jenom nástroj. Nemá žádnou citovou ani kulturní hodnotu, stejně jako ji nemá šroubovák. C má dosud své místo a své výhody, C++ byl odjakživa hrozný paskvil. Doopravdy neumře nikdy stejně jako neumře COBOL, ale jak se člověk jednou zbaví Baby Duck Syndromu a ocení výhody modernějších jazyků (v případě C++ tou modernější náhradou může být D, Rust, případně C# nebo i Python, podle typu aplikace), už je návrat k C++ těžko představitelný.
Áno, to se Vám nepochybně podaří, ale problém není ani tak v tom, že by C++ bylo špatné, ale v tom, že je to jazyk historický postavený na jiných programátorských paradigmatech dané doby. Před 20 lety byl považován za dobrého programátora ten, který uměl problémy s pamětí správně ošetřit. Dnes se řekne: „to není špatný programátor, že si nepohlídal všechny pointery“ … „to je tím, že jazyk je špatný“. Je to z toho důvodu, že jiné jazyky to hlídají za programátora, a tím se eliminovalo jedno z rizik programování (jeden z potřebných skillů programátora).
Navíc C++ při je ho postupné modernizaci se procházelo od konceptu C ke knihovně C++ s několika málo změnami po moderní jazyk (rok 2011+). Avšak s ohledem na zpětnou kompatibilitu se zachovaly možnosti psát „po staru“, a programátor má mnoho volnosti prasit dohromady konstrukty ze starého C, starého C++ a moderního C++.
To všechno dělá z C++ nebezpečný jazyk, a pokud chcete programátory donutit psát bezpečně, což se v praxi jaksi hodí, tak jim musíte C++ v současné formě zakázat. Je to smutné, ale je to tak, C/C++ umožňuje mnoho volnosti, ale bohužel ta volnost vede programátory ke špatnému používání jazyka a výsledkem jsou chyby.
Řešením je jedině omezit se (to lze vymáhat v analýzou kódu a v budoucnu lze předpokládat, že pokud C++ neumře, tak bude možné bezpečné standardy kódování vymáhat v lintu nebo i přímo kompileru) na moderní konstrukty (např. dle C++ Core Guidelines), které byly vymyšleny (a doplněny do C++) za tím účelem, aby se právě tyto chyby eliminovaly, z C++ se tak může stát jazyk podobný jiným moderním jazykům (ostatně nemálo těch konstruktů (C++11 až C++20) bylo převzato z jiných jazyků ve kterých se osvědčily).
Ano, C++ patří k těm jazykům, pro které platí „jaké si to uděláš, takové to máš“. Dalo by se říct, že to není programovací jazyk, ale nástroj, kterým si každý může vyrobit svůj vlastní programovací jazyk. Podle toho pak také vypadají diskuse, kde to vypadá, jako by každý psal o jiném jazyku – jenže ono to tak vlastně je. Problém je to právě u těch komplexních projektů, kde se potká spousta takových jazyků, všechny se syntaxí C++. Pak hodně záleží na tom, zda se těm schopnějším podaří vnutit ten svůj jazyk celému projektu.
Jenomže ono to není jenom o tom, že se musí používat moderní konstrukty (nemluvně o tom, že řada existujících knihoven včetně současného iostream prostě jako parametry bere char*). Je to o tom, že v C++ neexistuje lifetime analýza. Když například pořebuji v nějaké třídě mít referenci na jiný objekt, jsou v podstatě jenom dvě možnosti:
- buďto pracuji s nějakým unique_ptr nebo shared_ptr, což znamená, že tím vynucuji, jaký typ pointeru mi má volací kód předat, což hlavně u knihoven je problém;
- nebo přijmu referenci& (nebo pointer *) a v tu chvíli je po všem, protože v C++ není možné zajistit, že taková reference nepřežije objekt, na který ukazuje, že nemůže být nulová, nebo že nebude docházet k nekontrolovaným mutacím atd.
C++ je prostě děravé a je to jednak proto, že vzniklo v době, kdy pokročilejší metody statické analýzy prakticky neexistovaly, a jednak proto, že jeho filozofie vždycky byla implementovat všechny myslitelné featury a s problémy se potýkat "potom". V důsledku to vede i k takovým věcem, že najednou (pokud si pamatuju, tak v C++11) museli zavést novou alternativní syntaxi deklarace funkcí, protože s tou starou se jazyk stal neparsovatelný.
Jistě, že za pomocí analyzátorů a rigidní disciplíny je možné řadě problémů předejít, ale to není omluva a neznamená to, že C++ je vlastně dobré. Jestliže staré C++ bylo minové pole, tak moderní C++ je pořád minové pole, akorát je tam cedule "pozor miny". Rozhodně nevidím důvod, proč by měl někdo záměrně chtít jít zrovna tudy, pokud má jinou možnost.
26. 5. 2020, 09:20 editováno autorem komentáře
ad reference, teď vycházím z jednoho konkrétního projektu (v C), který je vystavený do internetu, takže to není jen o tom "na doma to stačí".
- nebo na daný objekt je omezený relativně malý počet referencí (nižší jednotky) v místech kde to dává smysl z pohledu performance, zaniká přesně v jediném místě (konkrétně potvrzená deautentikace klienta) kde jsou tyhle reference ošetřené a hlavne ošetřitelné, a v celém zbytku kódu se používá pouze v lokálních proměnných nebo jako parametr funkcí. Všude jinde, kde je jinde to potřeba uložit se použije unikátní serial, přes který se pak referencuje (reálně je pod tím btree ale to je fuk).
... a deauth je asynchronní evet v hlavním event loopu, takže race condition tam nemá vzniknout jak (bohužel, až do teď je to single thread, ale díky tomu výše nebude takový problém tam rozjet další, ale to už je jiná pohádka).
Ono se to dá, jen se člověk nesmí nechat unést.
Jistě že záleží na řadě okolností, mezi kterými jsou subjektivní (céčko mě osobně víc sedne než Java) i objektivní důvody (pointery jsou zlo, ale existuje spousta toolů a spousta návyků, které činí život s nimi snesitelný, a jde o zvážení jestli míru jistého nepohodlí z nich vyváží něco jiného, třeba ladění GC.)
Konkrétně u téhle věci je mnohem větší problém to, že se celý průběh hlavní smyčkou musí vejít do pár milisekund. Tady si troufám tvrdit že v tomhle konkrétním případě je céčko velmi vhodný jazyk, rozhodně bych ho nevnucoval jinde, zvlášť kde jsou jiné priority.
Před 20 lety byl považován za dobrého programátora ten, který uměl problémy s pamětí správně ošetřit.
Problém spatřuju v tom, že spoustu známých bezpečnostních chyb způsobili dobří programátoři. Možná ne tak dobří, aby splnili tuhle definici, ale dost dobří na to, aby se nedali snadno nahradit. A dost dobří na to, aby je drtivá většina zdejších čtenářů, ne-li všichni, respektovala. Protože chyby se stávají a nedají se eliminovat dodržením jednoduchých pravidel typu strcpy/strncpy/strlcpy.
On je tu jeste dalsi dulezity aspekt.
Dejme tomu ze jsem buh, co chyby v pointerech nedela, ani pri refaktoricazo apod, protoze mam hlavu jak patraci balon.
Otazka zni, jestli je stejny buh i ten Ind, co psal knihovnu pro odesilani SNMP trapu, kterou linkuju. Nebo libovoilnou jinou knihovnu, treba OpenSSL s jeho Heartbleed.
Ale ty přece také používáš C++ kód, který wrappuje C, který není bezpečný na všech platformách a vždy, např. používáš std::string tmpfile, který má problémy se staršími systémy, viz https://cwe.mitre.org/data/definitions/377.html.
U C++/C vůbec nejde o to, že umíš dobře psát, ale o to, že to dobře se nedá snadno ověřit a prokázat, vznikají chyby kombinací různých nepředvídatelných situací a máš tam jednu past vedle pasti.
Zaplatí prostě daň za bezpečnost.
Pokud se na objekt odkazuje několik objektů a chyba je v to, že jeden jim ho mění pod rukama, tak se to fixne vytvořením kopie (asi jako přiřazení proměnné v Erlangu). Vytvoření kopie chce paměť a čas.
Pokud odkaz přežije objekt, tak je dvojí obrana - neukazovat na objekt, ale při předání odkazu si ho naklonovat. Klon potřebuje paměť a kopírování (jedno, jestli se motá v cyklu, nebo čeká na DMA). Nebo počítat reference, občas se zastavit a projet to garbage collectorem (GC, který nezaměstná CPU, jsem ještě neviděl). GC je zátěž navíc, kolikrát projede všechny objekty v paměti bez toho, že by něco mazal...
No a pokud chci mít jistotu, že se někde něco nedomrví, tak nas..ru aserce úplně na všechno a ve všech funkcích. Už ti někdo řekl, že podmíněný skok je nejdražší instrukce kvůli zahazování pipeline? A že pokud budeš odskakovat jenom při chybě, otrávíš si branch prediktor?
Kde vidíš zachování nebo snížení spotřeby paměti/CPU?
A - tadá - takzvaně "bezpečnější jazyk" to řeší úplně stejně, akorát se to nemusí psát explicitně, takže ubude překlepů nebo opomenutí. Výkon pude tak jako tak do kopru.
Můžu se zeptat jak to dělá? (resp bavíme se doufám o dlouhodobé heap alokaci, a ne o triviálních či méně triviálních případech kdy zafunguje lifetime a dokáže to ošetřit kompiler)
Pokud mluvíte o std::rc::Rc tak tam si dost dobře nedovedu tu nulovou režii představit (ostatně ani v těch článcích, co jsem, rust neznaje, narychlo vygooglil, se v takovém případě nemluví o nulové režii, ale o režii srovnatelné s dobrou implementací v C/C++ - což mi připadá velmi uvěřitelné i logické)
Možná si nerozumíme (a možná nerozím já Vám co píšete v rámci rustu, který neznám).
Jde mi o zhruba následující, zcela hloupý, zjednodušený a neoptimalizovaný příklad. Mám server, přijme tcp connection, tomu naalokuje (na heapu) nějakou strukturu kterou strčím do nějakého seznamu, která obsahuje dejme tomu nějaké síťové detaily (socket, rcv a send buffer + head a tail na ně, nějakou stavovou proměnnou, případně nějakou vyšší abstrakci nad tím) plus string nickname. Celá ta veselost umí jen poslat někomu jinému zprávu, takže fajn, v rámci obsluhy vyparsuju co přišlo, udělám iteraci přes všechny connections a když sedí nick, tak tomu předám zprávu do send bufferu, zavolám write() a hotovo. (neřešme teď chyby, blocking etc., jde mi jen o datové struktury)
No a pak si vymyslím featuru, že když se někdo odloguje, tak to má napsat všem, s kým si povídali. Takže mě napadne ke každému connection přihodit nějaký seznam, který _nějak_ (v céčku to budou pointery, v rustu nevím a tam směřuje onen dotaz) ukazuje na connections účastníků, které je třeba notifikovat.
Tady kompiler nemá jak během compile time poznat živost (prostě objekt zmizí ve chvíli, kdy mu spadne tcp connection), a za běhu si nedovedu představit, jak by to (ať už automaticky nebo manuálně) mohl udělat bez přídavné režie, jak tu tvrdil předřečník. Kompiler můžu vygenerovat při zrušení reference automaticky decrementovat ref_count a při nule zavolat nějaký free()/dealloc() nebo jak se to jmenuje, ale jak psal předpředřečník zadarmo to není, nebo může jen dekrementovat referenci ale samotnou práci nechat na GC, celé to samozřejmě může co do taktů velmi zlevnit optimalizace překladu (proč inkrementovat ref_count když vím že ho hned zase dekrementuju, teda pokud to není multithread, ale to je jen detail a měli bysme podobnou diskusi kolem Arc), ale cena na paměť tam bude pořád (minimálně je to o sizeof(refcount) interně víc - to že v 99% RL aplikací na tom nesejde je věc druhá)
Nebo jsem jen pochopil špatně, a reálně se v rustu podobné konstrukce dělají úplně jinak?
Zázraky se nedějí a inherentní výpočetní složitost se obejít nedá. Rust člověka nepustí tam, kde to není bezpečné, ale to neznamená, že to program zpomalí nebo zvýší paměťové nároky. Synchronizace mezi vlákny má samozřejmě vždycky režii a ta by byla i v dobře/bezchybně napsaném programu v C. Vtip je v tom, že v Rustu by neměla být větší a pokud člověk nepoužívá kanon na vrabce, nedojde k jevu, kterým hrozí Petr M. Akorát jako bonus dostaneme tu větší jistotu a případně tedy stabilitu.
Přemýšlíte o tom způsobem vhodným pro jazyky s GC. V C++/Rustu tak jde přemýšlet taky, ale není to úplně šikovné. Nebudu se soustředit na implementační detaily, ale vezmu to obecně.
Objekty v jazycích s GC existují naprosto nezávisle. Prostě žijí minimálně tak dlouho, dokud o nich někdo ví. A až na ně všichni zapomenou tak možná někdy umřou. Objekty v jazycích s GC nemají vlastně dobře ohraničený konec života. GC svým způsobem emuluje nekonečnou paměť, kdy objekty jen vytvářím a až doslouží tak je prostě ignoruju.
Naproti tomu v C++/Rustu se vychází z toho, že většina objektů má nějakého logického vlastníka. Jen minimum objektů má cenu vlastnit sdíleně třeba přes reference counting. Například ten váš seznam lidí k notifikaci nemá důvod existovat samostatně bez toho primárního spojení. Takže bude mít jediného vlastníka a i jeho život bude s tím vlastníkem provázaný.
A život záznamu v tabulce těch notifikací je zase svázaný s životem toho spojení s protistranou. Ve chvíli, kdy nějaké spojení umře, tak umřou i všechny vlastněné objekty.
Ten příklad je hodně vágní, takže je těžké mluvit o nějakých konkrétních datových strukturách. Ale nevidím tam vlastně nic, co by vůbec vyžadovalo sdílení vlastnictví a tím i reference counting.
Hlavní rozdíl v uvažování je ten, že pokud v jazyce s GC někam předáváte ukazatel, tak si ho ten volaný může bez omezení uložit a prodloužit tomu objektu život.
V C++ to není dobrý nápad, takže to dělá (v novém c++) málokdo. Když předávám ukazatel, tak předpokládám že si ho volaný nebude nikam ukládat a po návratu z funkce už ten ukazatel neexistuje. Pokud chci volanému předat vlastnictví, tak dostane smart pointer. Jinak to dělá akorát historický kód, případně nějaké zprasenosti.
Rozdíl mezi C++ a Rustem je v tomhle jen ten, že mi borrow checker vynutí abych ten půjčený ukazatel zase vrátil a nenechal si ho. V C++ je to jen dobrý zvyk, který ale překladač nemá jak vynutit.
Jak moc je ten koncept vlastnictví „přirozený“? Vždycky, když o tom čtu, je to velmi logické – a zároveň vím, že kdybych to měl začít používat, budu nad tím muset strašně uvažovat, není to něco, co bych udělal intuitivně a většinou správně. Je možné, že je to jen nezvyk – ale trochu se bojím, že ne, že to prostě v něčem nesedí do světa, jak ho jako lidé normálně vnímáme. Ale chybí mi ta zkušenost, takže by mne zajímal názor někoho,kdo tu zkušenost má.
Zkusím to připodobnit ještě k něčemu jinému. Třeba relační databáze jsou podle mne tak úspěšné proto, že používají model, který je lidem nějak blízký, je pro ně přirozený – model relačních databází existoval už dávno před počítači v podobě kartotéčních lístků nebo podvojného účetnictví. Podobně je to třeba s některými částmi objektového paradigmatu – a některé části, které nemají pořádný předobraz v reálném světě (třeba dědičnost), jsou i v OOP problematické a buď se nepoužívají, nebo se používají divně.
Ten koncept vlastnictví je z hlediska OOP paradigmatu vlastně správně, uzavírá určitou díru, která je v běžných OOP jazycích a týká se zapouzdření. Normálně by měl objekt sám rozhodovat, co se s ním dá dělat, k tomu vystaví potřebné metody (nebo reaguje na události). To, že ten objekt může vlastnit kdokoli, ale to zapouzdření porušuje – protože pak platí, že o tom, co se s objektem dá dělat,rozhoduje objekt sám, s výjimkou vlastnictví, protože vlastnit ho může kdokoli.
Rust tuhle díru v designu zalepil – ale odpovídá tenhle model tomu, jak vnímáme reálný svět? Já se bojím, že spíš ne, protože mu neodpovídá ani zapouzdření. Ano, objekt pes obvykle běhá, štěká, kouše a žere, ale pak přijdete s Bóbikem do restaurace a ukáže se, že se psem lze dělat i jiné věci, které Bobík určitě nechtěl. Nebo vám po přivyknutí připadá koncept vlastníka přirozený, rovnou vás napadá, kdo má být vlastník a co zpřístupníte ostatním – a jakmile se vrátíte do jazyka se sdíleným vlastnictvím, připadá vám to najednou jako hrozná anarchie, že objekt může vlastnit každý, kdo chce?
Koncept vlastnictví samozřejmě v obecném pojetí přirozený není a troufám si tvrdit, že většina algoritmů ho nevyžaduje. Je to tedy nutné řešit v jazycích, které nemají GC, což má pak nezanedbatelný vliv na algoritmus, kód, čas programátora atd. V podstatě programátor musí zas a znovu ten GC v nějaké formě zapracovat do řešeného problému.
Jestli je "přirozený" nevím. Mám pocit, že v našem oboru není přirozené vůbec nic. Všechno je jen o naučení se, zvyku a hromadě tréninku. A jestli můžu vzít za slovo Daniela Kahnemana a jeho Rychlé a Pomalé myšlení, tak je to stejně i jinde. Veškerá naše intuice stojí na tom, že si natrénujeme mozek na podobných situacích. Něco úplně nového intuitivně a správně dělat prostě neumíme.
Jinak já často ani neuvažuju o objektech jako samostatných entitách. Proměnné jsou obvykle spíš chlívky na hodnoty. Hodnotovou sémantiku v C++ bych nejlíp popsal stylem "Když můžeš, tak se chovej jako int". Proč by třeba string měl být nějaký objekt na haldě, na který se může vést hromada odkazů? Proměnná typu string je prostě chlívek na string a nějakou alokaci paměti ať si řeší uvnitř. Když nemám odkaz na string, ale přímo string, tak to vlastnictví vyplyne už z toho, kde ta proměnná je.
OOP paradigma a reálný svět jsou dost vzdálené. Podobnosti jsou IMO spíš na škodu a slouží hlavně k tomu, aby začátečníky vodily stále do stejných pastí. V reálném světě děláme něco my s objekty, v OOP světě dělají něco ty objekty samotné. Drtivá většina reálných objektů umí akorát tak "zůstaň". Kdesi jsem četl vyjádření samotného Alana Kaye, že se mu ten název moc nepovedl.
Nevím, jestli si pamatujete svoje OOP faily, já ty svoje jenom částečně. Určitě jich bylo mračno, než jsem si natrénoval hlavu.
Mám pocit, že lidi co tu píšou pesimisticky o C++ v něm kdysi možná dělali, ale teď už nemají vůbec přehled. Nedávno byl v Praze schválen nový standard C++20 s největší účastí co kdy byla. Nová verze je každé 3 roky. Jak gcc, clang, tak Visual Studio adpotují nové věci už v průběhu návrhu nového standardu. Vývoj jde naopak rychleji než kdy předtím.
https://www.reddit.com/r/cpp/comments/f47x4o/202002_prague_iso_c_committee_trip_report_c20_is/
Nevypořádal ses s konkrétními připomínkami v diskusi, zejména:
1. Složitost C++, které si i přes další a další revize všechen ten balast z minula nese s sebou.
2. Absence lifetime analýzy, která vede k chybám i v moderním C++.
3. Problémy s parsováním deklarací funkcí vyřešené alternativní syntaxí s klíčovým slovem auto. A dodávám já - celkový syntaktický horor oproti různým konkurenčním jazykům, byť je vidět, že autoři C++ dělají co mohou.
Určitě máš pravdu, že nové verze jsou o něčem jiném a konkrétně třeba zavedení modulů (konečně!) je velký posun kupředu. Jak se ale v moderním C++ formátují řetězce? V Novákově repozitáři, který zde odkazuje, vidím třeba
var1 + " - " + var2 + ": " + var3
V jiném příkladu zde v diskusi vidím nechvalně známé
cout << "Hello world" << endl;
Dost hrůza. Už na tohle existuje něco rozumného nebo se to aspoň chystá?
26. 5. 2020, 12:29 editováno autorem komentáře
1) To je základní vlastnost jazyka se kterou musí člověk počítat. Zpětná kompatibilita je pro velkou část uživatelů C++ zásadní. Maximálně se uvažuje o nějakých epochách jako v Rustu.
2) Ano není součástí C++. Už jen kvůli bodu jedna to ani není možné. To by znamenalo udělat nový jazyk. Pro statickou i dynamickou analýzu je plno nástrojů součástí všech hlavních překladačů. A zrovna lifetime je něco co v moderním C++ člověk prakticky neřeší.
3) Nevím přesně o jaké problémy s parsováním se jedná. Nové verze je zejména pro automatickou detekci návratové hodnoty. Používá se zejména pro zjišťování
návratové hodnoty z šablonových parametrů. Pokud si tam dáte konkrétní typ, tak to už je na vás. C++ vás neomezuje.
4) Je dobře že se ptáte zrovna na formátování. V C++ 20 je nová knihovna format.
https://en.cppreference.com/w/cpp/utility/format
1) Nemyslím si, že k tomu v dohledné době dojde. Nikdo nikoho nenutí psát pro C++ překladač v C, a přitom to v podstatě jde. Je to v mnoha ohledech nevýhoda, ale v současné době, kdy se klidně programovací jazyk v nějaké verzi zažízne a hotovo, to je možná i výhoda. Dá se postupně psát nové věci v novém standardu, a není nutné hned vše přepisovat do nového.
2) Není zač.
3) Toto řešení se podle mě zvolilo, protože byla požadována nová vlastnost, která se starou syntaxí snad ani nešla udělat. Čili se muselo vytvořit něco nového. Navíc to stejně funguje u lambda funkcí, kde návratovou hodnotu ani jinak určit nelze.
Souhlasím, že toho syntaktického balastu je hodně, ale to by se muselo jinak zavádět ještě mnohem více klíčových slov, a nebo odříznout tu zpětnou kompatibilitu. V C++ 20 je např. nová syntaxe pro koncepty, takže velikost balastu se sice sníží, ale člověk aby se učil novou syntaxi :D. Ale nikdo vás nenutí k nové syntaxi, díky kompatibilitě člověk může dál psát ten balast :D.
V moderním C++ se řetězce formátují pomocí https://en.cppreference.com/w/cpp/utility/format
Pro starší c++ se dá použít takřka identická knihovna fmt.
a zase mám s tou novou vychytávkou trochu problémy. Já třeba používám referenci indexem při formátování.
logDebug("V domu je $1 stenata a $2 kotata", cstenat, ckotat)
Pokud někdo bude chtít hlášku přeložit a přehodit štěňata a koťata, určitě zvládne přehodit čísla u $
std::format("V domu je {} stenata a {} kotata", cstenat, ckotat)
(jen příklad, zapomeňme nyní na problémy s češtinou, číslovky a pády)
> Nová verze je každé 3 roky
Ještě je dobré dodat, že polovina novinek jsou rovnáky na vohejbáky, čímž je krásně ukázáno, jaký bordel v tom jazyku je (tedy spíš je to špatnou koncepcí) a kolik dalšího bordelu se s každou verzí přidává. Nemluvě o tom, že ty nové konstrukty nejsou ortogonální, čímž se programátorské peklo nezadržitelně prohřívá...
V každém dlouhodobě vyvíjeném jazyce časem přibývají rovnáky a ohýbáky na věci, které se v minulosti nenavrhly dobře.
Řešit to formou - naučím se nový jazyk - který časem stejně bude plný rovnáků a ohýbáků - není řešení.
(nebavme se o C++, vzpomenu si na Javu, nebo na Python, ale i ten módní Rust už má v sobě dost rovnáků, konečně celý Rust mi přijde jako jeden velký rovnák a ohýbák na C ve stylu "C++ je fuj, narovnejme C)