Podle mě ze stejného důvodu, proč je to v Go - při parsingu (jak počítačem, tak při čtení zdrojáku člověkem) není zpočátku jasné, jaký objekt se deklaruje; musí se vlastně dojít až na konec celé deklarace a tam se rozhodne (jestli je to funkce, konstanta nebo proměnná). Takže tam přidali to klíčové slovo. A navíc to potom umožňuje i čitelný zkrácený zápis funkce s tělem za =>
Jinak osobní názor (který se do článku nehodí): jako je to pěkné, některé myšlenky v C3 jsou zajímavé, ale C to myslím nenahradí. To ale zatím ani žádný jiný jazyk zmíněný v článku. Největším plusem je naprosto skvělá podpora C ABI, ale i autor C3 je obecně skeptický: https://c3.handmade.network/blog/p/8486-the_case_against_a_c_alternative
Nicméně pro psaní aplikací - na druhou stranu proč to nezkusit.
Nedávno jsem zrovna přepsal několik programů z C3 do Rustu jako takový experiment. Jeden mám dokonce veřejně (C3, Rust).
Ve výsledku mi přijde, že C3 má lepší error handling, lepší makra
a snáze se volají systémové funkce.
V Rustu jsem si o něco jistější, že nepřistupuji k nějaké paměti, co nemám, ale občas to bylo za cenu ošklivějšího kódu (například nemohu do nějaké funkce předat mut referenci na strukturu, pokud na field dané struktury mám referenci jinde, i když by mutable přístup ke struktuře neměnil field, co už jinde referencuji - tohle typový systém Rustu nezvládne zachytit).
Hlavní nevýhoda Rustu mi přijde složitost psaní vlastních datových struktur - dokážu ji napsat v unsafe kódu, ale už bohužel nedokážu vytvořit bezpečné rozhraní. Ta složitost Rustu je vidět například na node.rs ze standardní knihovny. Když jsem to přepsal do C3, tak se velikost zmenšila skoro na třetinu.
Chápu supbjektivní představu ošklivosti.
Chápu, že v Rustu se některé věci dělají složitě.
Když píšete, že jste "to přepsal do C3, tak se velikost zmenšila skoro na třetinu", bylo nebo nebylo to za cenu toho, že kompilátor ztratil přehled o zárukách?
Stejně jako je pro někoho důležité, aby kód byl stručný a krátký, tak pro mě je zase důležité, aby stroj poskytoval nějaké záruky. Podle mých informací je C3 unsafe by default, na rozdíl od Rustu, který je naopak safe by default. Chápu to správně?
> Když píšete, že jste "to přepsal do C3, tak se velikost zmenšila skoro na třetinu", bylo nebo nebylo to za cenu toho, že kompilátor ztratil přehled o zárukách?
Zrovna v tomto konkrétním souboru se asi o žádnou záruku nepřišlo anebo jich bylo naprosté minimum (jediné, co mě teď napadá je, že místo ukazatele NonNull používám v NodeRef.node normální ukazatel). I původní kód v Rustu používá hodně unsafe a věci jako MaybeUninit nebo ukazatele. Naopak v C3 nehrozí tolik chyb s aliasingem jako v Rustu, kde si celá implementace musí dát veliký pozor, aby např. nevrátila třeba 2 mut reference na tutéž věc.
Součástí implementace v Rustu jsou pak další soubory, které se snaží vybudovat safe rozhraní. Ty jsem také zahodil, ale ty do porovnání velikosti nepočítám. Moje implementace má totiž o dost flexibilnější rozhraní a dovoluje dělat věci, co safe implementace v Rustu neumí (např. moje porovnávací funkce nemusí porovnávat klíče stejného typu K).
Pro mě je C++ moc složité, chybí tam důležité funkce a naopak tam jsou zbytečnosti.
Například preferuji používat vlastní alokátory před RAII, preferuji mechanizmy chyb ze Zigu nebo C3, případně Result z Rustu, před výjimkami (abych věděl, co může skončit chybou, případně jakou). A preferuji compile-time reflexi (jako má třeba Zig nebo C3) před šablonami v C++ (něco takového chtějí přidat i do C++, ale v jiných jazycích už to je).
Naopak nepotřebuji dědičnost, RAII, virutální funkce a šablony mi stačí jen místo generik.
Tak já RAII používám dost masivně, ani si nedokážu představit, že bych to psal jinak. Třeba že když opustím objekt transakce, tak se mi sama commitne, nebo když opustím zámek, tak se mi zámek odemkne... atd...
Co se Result vs výjimky - nevím no, vždycky si člověk řekne, tady výjimky nepoužiju a pak skončí tím, že všechno vrací chybu a všechno musím ošetřovat. Rustovsky "když error tak return error" (aka ?), je už skoro jak výjimkový systém, akorát se o tom nesmí mluvit.
U těch výjimek/chyb mi přijde důležité, zda vím, jaký kód je vyhazuje a jaký ne. Případně i jaké výjimky. Občas je dokonce fajn vědět, zda může nastat chyba, protože došla paměť.
> Třeba že když opustím objekt transakce, tak se mi sama commitne, nebo když opustím zámek, tak se mi zámek odemkne
Občas se to hodí. Ale třeba u transakcí si radši sám určím, zda se má rollbacknout nebo commitnout, a nevadí mi to mít explicitně v kódu.
U těch transakcí jsem to měl tak, že jsem musel explicitně označit transakci za úspěšnou, aby se v destruktoru commitla, jinak byl rollback. Ještě "línější" řešení je, když destruktor transakce se dívá, jestli neletí výjimka. Pokud letí, udělá rollback, jinak commit. Ale s tímhle řešením si nejsem jist. Vždycky ale ten objekt transakce má možnost manuální řízení (jako unique_lock)
Jak říkám u ošetření chyb - ze všeho může vypadnout chyba.
A pak tady máš chyby které spíš nenastanou. Například mám program, co komunikuje s externí službou přes JSON. Šance, že by ze služby vypadl nevalidní JSON je prakticky nulová. Takže vůbec tuhle situaci neošetřuju, netestuju. No ale přesto se tam hodí mít try - catch na nějaké základní úrovni, která pořeší i výjimku s nevalidním JSONem.
C++ rozhodně s C kompatibilní není. Co hůře některé stejně vypadající konstrukty a klíčová slova majíí v C a C++ zcela jiný význam (např. inline ... v C znamená že se má funkce inlinovat, v cpp to znamená že ji definujete jako slabý symbol pro linkování a má být deduplikována, nebo třeba typická zrada, kdy "string" je v C char* ale v cpp const char*).
No, zcela jiný význam...
Inline v C taky "jen" umožňuje inlinování tím, že řeší konflikty symbolů při linkování. Jen to dělá malinko jinak. Takže v C je třeba udělat trochu víc práce, aby se úspěšně slinkoval i debug build. Tam i tam to pak překladače můžou interpretovat i jako hint, že se to zainlinovat má.
V C jsou sice string literály char *, ale zápis je nedefinované chování. Takže to člověk do toho const char * chce přiřadit už jenom proto, aby si náhodou nenaběhl na vidle.
ahoj, díky.
Ale jo překládal, ale originál v repu https://github.com/tisnik/c3-examples/blob/master/introduction/renderer.c ne to, co je vloženo do článku.
Při transformaci do HTML (ty jeho > atd.) se asi něco...nepovedlo... Díky za upozornění, hned opravím.
Update: tak opraveno, ještě jednou dík.
11. 9. 2025, 10:10 editováno autorem komentáře