Teoreticky ano, prakticky, když ve svém API něco změní a bude ignorovat části jádra napsané v rustu, jádro se nejspíš nezkompiluje. A patche které rozbíjí kompilaci se obvykle nezačleňují. Takže bude muset nejspíš při každé takové změně čekat, až správci částí napsaných v rustu interface opraví, nebo opravu udělat sám. To bude zřejmě důvod, proč se pronikání rustu do jádra tak zuřivě brání.
Jestli chce sahat jiným maintainerům do jejich kódu, tak to je snad prinicipiálně špatně nejen při vývoji kernelu a bez ohledu na to, v čem je jejich část napsaná. Jemu po tom přece vůbec nic není. Ta hranice je jasně daná, on nabízí API, oni ho používají. Jak ho používají, je na jejich rozhodnutí a jejich odpovědnosti. A že udělá nekompatibilní změnu, které se ostatní musí nejprve přizpůsobit, než může jít do buildu? Tak si holt počká, jeho problém. Aspoň si takové změny pořádně rozmyslí.
otazka je dokedy to odpadava
teraz vsetci rustaci tvrdia, ze oni su s tym ok, oni si to opravia, lenze historia uci, ze toto plati len urcitu dobu a casom sa na tie povodne sluby zabudne a zacnu sa klast dalsie poziadavky a co bolo, to bolo terazky ziadame iny pristup
vie niekto cim je ten rust taky vynimocny, ze ho linus a jeho partia zobrali na milost a povolili ho pre vyvoj jadra? a preco ostatne jazyky v pokuse dostat sa do linusovej priazne neuspeli?
Ano, presne taketo spravanie ocakavam.
Pri ruste je este jedna vec - je to jazyk definovany svojou jednou implementaciou. C a C++ maju specifikaciu, specifikuju ich prislusne pracovne skupiny pozostavajuce z clenov rozlicnych organizacii a existuje viacero nezavislnych implementacii, aktualne najvacsie tri su msvc, clang a gcc. Pokial by organizacia za niektorou z implementacii zacala blbnut, nie je to az taky problem, pouzije sa ina (mozno s tejakymi technickymi problemami, ale zvladnutelne). Ale pokial zacne blbnust rust governance, tak potencionalne miliony investovane do pisania nejakeho sw v ruste mozu byt v lufte. Je to riziko, ktore sa prehliada.
Hele, to se tak nějak očekává.
Výhoda linuxu je, že už existuje, nikoliv jazyk, ve kterém byl napsán.
Existuje alternativa v podobě RedoxOS. Jeho nevýhoda je, že v něm není to všechno co je v Linuxu. A pokud jsi někdy programoval tak asi víš, že přepisovat existující produkt do něčeho nového málokdy bejvá dobrý nápad.
A tak se to zkouší z druhé strany. Využívá se existující kód, ale novosti se píšou v moderním jazyku s představou, že by to mohlo dávat ekonomicky větší smysl. Ten směr; volba jazyka je logická, tam není o čem.
Samozřejmě stát se může všechno. Třeba Linus vyměkne, a Rust půjde z jádra pryč. A pak by experimenty jako je RedoxOS dostali větší impuls, a taky by se mohlo stát, že by Linux začal upadat.
21. 2. 2025, 20:20 editováno autorem komentáře
>>> A pokud jsi někdy programoval tak asi víš, že přepisovat existující produkt do něčeho nového málokdy bejvá dobrý nápad.
Vtipy stranou, v predchádzajúcej robote sme presne také robili. Mali sme referenčnú implementáciu a zákazníkovi dodali implementáciu pre jeho platformu. Kladie to ale vyššie nároky na dokumentáciu (Tú developeri väčšinou podceňujú).
Napríklad reimplementácia GNU utilít v rust celkom slušne napreduje.
https://github.com/uutils/coreutils
Chápem, že s kernelom to bude asi horšie, ale tak uvidíme. Jasnovideckú guľu nemám.
Příkladem jsou třeba mutexy. V Rustu jsou zamykaná data uvnitř Mutexu (což je změna rozhraní oproti C, na kterou se ptáte). Na jednu stranu je to výhodné, protože pak nemůžete udělat chybu, že byste zapomněl zamknout, když byste měl.
Jenže na druhé straně vás to nutí zamknout, i když k datům přistupuje pouze jedno vlákno a ostaní vlákna jen drží referenci, kterou momentálně nepoužívají. Nebo není možné sdílet jeden mutex pro více proměnných, aniž byste je sdružil do jedné struktury (najednou má tedy Mutex vliv na rozložení dat v paměti).
A pokud máte situaci, že v jednu chvíli chcete jedním Mutexem zamykat více proměnných naráz a jindy chcete pro každou z těchto proměnných separátní Mutex, tak to nejde. Jinak řečeno, strategii zamykání nejde měnit dynamicky.
Samozřejmě, že to jde, a v kernelu pravděpodobně podobných věcí bude dost. To, co popisujete, je Mutex ze stdlibu Rustu, který je bezpečný na použití. Kdokoliv si ale může vytvořit vlastní mutex, který bude mít ty vlastnosti, ktere popisujete (akorát pak může třeba jít použít špatně, takže může mít unsafe metody, ale to už je věc trade-offu).
Jenze i jeden radek unsafe kodu muze porusit invarianty, na kterych zavisi safe kod. Napriklad kdyz v unsafe kodu vytvorim druhou &mut referenci na nejakou hodnotu, tak ma kod nedefinovane chovani.
Prikladem je funkce NodeRef.len, ktera ani nic nezapisuje, ale jeji zavolani v nevhodnou chvili muze rozbit invarianty, na kterych kompilator zavisi. Ty invarianty jsou bohuzel slozitejsi na kontrolu nez v C/C++, takze IMO spis udelate chybu v unsafe Rustu nez v C.
> Ty invarianty jsou bohuzel slozitejsi na kontrolu nez v C/C++
Jak. Opravdu by mě to zajímalo, tvrdíš to už minimálně v druhé diskuzi, ale pořád nevím co je v C++ snazší mimo "je snazší ignorovat je"
> Jenze i jeden radek unsafe kodu muze porusit invarianty, na kterych zavisi safe kod. Napriklad kdyz v unsafe kodu vytvorim druhou &mut referenci na nejakou hodnotu, tak ma kod nedefinovane chovani.
Narozdíl od C/C++, kde takovou schopnost má všechno, takže se při debuggingu musím zaměřit na mnohem větší část kódu a při vývoji se musím soustředit na mnohem větší část kódu.
Momentálně v práci pracujeme na poměrně low-level kódu, který se místy na unstafe potřebuje spolehnout. Při editaci kódu kolem unsafe je potřeba zajistit, aby se unsafe kód neocitl v kontextu kde bude unsound, takže pár bloků kódu. Při editaci C++ kódu je potřeba hlídat úplně všechno.
Jak. Opravdu by mě to zajímalo, tvrdíš to už minimálně v druhé diskuzi, ale pořád nevím co je v C++ snazší mimo "je snazší ignorovat je"
Jedná se třeba o aliasing. C konzervativně předpokládá, že ukazatele a reference na stejný typ mohou být aliasy (pokud nepoužijete restrict), zatímco Rust u mut referencí předpokládá, že ne a nechává na programátorovi, aby to zajistil. Pokud to programátor nezajistí, tak má nedefinované chování.
Takže pokud to chápu dobře, tvoje premisa je "Kompiler může chybně předpokládat že dva pointery nejsou aliasy" a zoptimalizovat kód na něco co je UB.
Popravdě, jak se chová kompiler k unsafe v kontextu aliasingu jsem nevěděla, ale podle všeho ten předpoklad u unsafe neuplatňuje a neprovádí relevantní optimalizace. https://www.reddit.com/r/rust/comments/1ery9dy/comment/li1zkk2/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
Takže: C umožňuje aliasy všude. Rust jen v unsafe blocích. Rust navíc díky tomu lépe optimalizuje kód mimo unsafe, kde aliasing hlídá za programátora.
> Kompiler může chybně předpokládat že dva pointery nejsou aliasy
Dvě mut reference na jednu hodnotu jsou UB (i když se jedna z nich třeba nepoužívá). Momentálně takový kód sice většinou po přeložení funguje, ale kdykoliv může vyjít nová verze Rustu, která to přeloží na nějakou podivnost, co programátor nechtěl.
> C umožňuje aliasy všude. Rust jen v unsafe blocích.
Ano, C je více konzervativní a aliasy předpokládá, pokud kompilátor nedokáže opak. Naopak Rust u mut referencí aliasy nepředpokládá.
> Rust navíc díky tomu lépe optimalizuje kód mimo unsafe, kde aliasing hlídá za programátora.
Ano. Dokonce možná i v unsafe lépe optimalizuje mut reference (nebo by mohl). Ukazatele v Rustu tuhle vlastnost nemají. Ty fungují jako v C. Čehož využívá i standardní knihovna Rustu - na některých místech drží více ukazatelů na jednu hodnotu, ale dává si pozor, aby neměla více než jednu mut referenci.
Samozřejmě, může, proto se jmenuje "unsafe". V praxi je tedy snaha jeho použití minimalizovat, a když už ho někdo použije, není to jednoduché a musí se snažit udělat to správně (existují nástroje, které s tím pomáhají). Např. tebou zmiňovaná funkce v NodeRef je přístupná pouze uvnitř implementace BTreeMap, celý NodeRef vůbec není přístupný zvenčí, pokud dobře vidím.
Není mi jasný smysl tvojí argumentace. Tvrdíš, že C je bezpečnější než Rust, protože (...důvody výše..)? Pokud ano, moje zkušenost je opačná, ale samozřejmě nemůžu vyloučit, že ve tvé specifické nice je to naopak, např. právě kvůli důvodům, které popisuješ a se kterými se možná ve své bublině (nemíním urážlivě) potkáváš. Co sleduji diskuze vývojářů Rust for Linux, přijde mi že ti vypadají s Rustem v Linuxu spokojeně, a o nich IMO tato zprávička je.
celý NodeRef vůbec není přístupný zvenčí, pokud dobře vidím.
Ano, ale to nic neřeší. Ten kód můžete volat nepřímo tím, že používáte BTreeMap. A pokud to nepřímo jde zavolat tak, že se poruší nějaké invarianty, tak máte v programu nedefinované chování.
Tvrdíš, že C je bezpečnější než Rust,
Ano, pokud potřebujete psát unsafe kód, což IMO v jádře bude nastvávat častěji.
Co sleduji diskuze vývojářů Rust for Linux, přijde mi že ti vypadají s Rustem v Linuxu spokojeně, a o nich IMO tato zprávička je.
Tahle zprávička je o tom, že s tím nejsou spokojeni všichni vývojáři jádra a Linus to někomu v podstatě tlačí silou.
Až na to, že třeba takový GKH s Vámi nesouhlasí. Přímo vyjmenovává, že většina chyb a CVE, které řešil, byly způsobeny nějakým C detailem, který byl přehlédnut a v Rustu by se pravděpodobně nestaly.
https://www.phoronix.com/news/Greg-KH-On-New-Rust-Code
"The majority of bugs (quantity, not quality/severity) we have are due to the stupid little corner cases in C that are totally gone in Rust. Things like simple overwrites of memory (not that rust can catch all of these by far), error path cleanups, forgetting to check error values, and use-after-free mistakes. That's why I'm wanting to see Rust get into the kernel, these types of issues just go away, allowing developers and maintainers more time to focus on the REAL bugs that happen (i.e. logic issues, race conditions, etc.) "
Ad "forgetting to check error values" - tam může v C pomoci __attribute__ ((__warn_unused_result__)) nebo [[nodiscard]].
> a v Rustu by se pravděpodobně nestaly.
Hodně těch chyb jde udělat i v safe Rustu nebo i jiných "bezpečných" jazycích s GC. Příkladem je třeba pool implementovaný pomocí pole, kde omylem přistupujete k hodnotám, které ještě nebyly inicializovány, nebo už byly označeny jako uvolněné.
Druhá věc je, že některým problémům jde předejít jinou organizací kódu.
> these types of issues just go away,
IMO není pravda. Naopak, čím komplexnější kód v jádře bude (a Rust je krok tímhle směrem), tím víc bugů se tam objeví. Podívejte se, jak pokročily programovací jazyky, mnoho SW je v "bezpečných" jazycích s GC, ale paradoxně je vše stále plné chyb. Proč bych měl věřit, že Rust to nějak změní? Zvlášť, pokud na psaní jádra nebude stačit safe Rust, ale bude se muset použít unsafe, který IMO je složitější než C.
> Zvlášť, pokud na psaní jádra nebude stačit safe Rust, ale bude se muset použít unsafe, který IMO je složitější než C.
Co jsem tak četla zkušenosti lidí kolem Asahi,
1) díky Rustu objevili i spoustu chyb v C kódu kolem
2) unsafe nebyl nijak závratný problém, ten povrch který musel zůstat unsafe byl dost marginální.
Pokud se podíváme na jiný rozsáhlý projekt, kde je C/C++ nahrazované Rustem, data mluví za vše. https://www.theregister.com/2024/09/25/google_rust_safe_code_android/
> Ano, ale to nic neřeší
IMHO řeší. Čím zanořenější unsafe bude, tím menší je šance, že kód nedovolí "bořící" invarianty.
>> Tvrdíš, že C je bezpečnější než Rust,
> Ano, pokud potřebujete psát unsafe kód, což IMO v jádře bude nastvávat častěji.
Mě to tedy logicky nedává smysl, ale respektuji.
> Tahle zprávička je o tom, že s tím nejsou spokojeni všichni vývojáři jádra a Linus to někomu v podstatě tlačí silou.
Tak jsem ten mailing teda nepochopil.
Jsou tu lidé, kteří nemají Rustu nerozumí, a nemají ho rádi, nevěří mu.
Linus tlačí, nebránit zkoušet používat Rust.
To je přesný popis. Ale naštěstí v Rustu jsou tyto části explicitně ohraničené (a také ve spoustě aplikací jsou extrémně vzácné), a dají se tak mnohem jednoduššeji zkoumat a reviewovat. A hlavně se nad nimi dá postavit bezpečné rozhraní, které zaručuje, že ten unsafe blok nepůjde použít špatně (z pohledu UB/memory safety).
V C a C++ je celý kód unsafe, a v podstatě každý řádek může obsahovat UB (a tím pádem také rozbít celý program). To je obrovský rozdíl.
> A hlavně se nad nimi dá postavit bezpečné rozhraní, které zaručuje, že ten unsafe blok nepůjde použít špatně (z pohledu UB/memory safety).
Jde to, ale je to těžké. Viz třeba bugy ve standardní knihovně nebo owning_ref nebo bugy co našel nástroj Miri.
Můj názor je, že jazyk by měl být co nejjednodušší, aby kód v něm bylo možné snadno překontrolovat. Což bohužel unsafe Rust nesplňuje a C je na tom lépe.
> Můj názor je, že jazyk by měl být co nejjednodušší, aby kód v něm bylo možné snadno překontrolovat. Což bohužel unsafe Rust nesplňuje a C je na tom lépe.
Tvrdíš, že krátký kód se kontroluje hůře (Rust unsafe) než dlouhý kód (C) ?
Tvrdíš, že člověk je schopen mentálně pojmout libovolně velké množství kódu?
Pozn: Rust unsafe je krátký kód, který se píše proti API Rustu. Takže není nutné kontrolovat safe a unsafe zároveň.
> Tvrdíš, že krátký kód se kontroluje hůře (Rust unsafe) než dlouhý kód (C) ?
Často je kód v Rustu delší než v C-like jazycích. Důvodem je, že tam je více druhů referencí a ukazatelů a stejnou věc implementujete několikrát.
Například jsem překládal B-strom z Rustu do C3 a vkládání se zmenšilo z 1000 řádků v Rustu na 400 řádků v C3 (včetně komentářů). Stačilo jen vypustit funkce, které něco přetypovávají, aby to uspokojilo typový systém Rustu.
impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
/// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe
/// because the return value cannot be used to destroy the root, and there
/// cannot be other references to the tree.
pub(super) fn borrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}
/// Slightly mutably borrows the owned root node.
pub(super) fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}
/// Irreversibly transitions to a reference that permits traversal and offers
/// destructive methods and little else.
pub(super) fn into_dying(self) -> NodeRef<marker::Dying, K, V, Type> {
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}
}
Všimněte si, že všechny funkce mají stejné tělo. Je to balast, který v C není třeba.
Takže tvrdím, že kratší kód v C se reviewuje lépe než delší kód v Rustu, kde jsou hromady balastu a duplicit. Nebo podobně dlouhý kód v unsafe Rustu, který je mnohem těžší na kontrolu.
Doufám, že tě chápu dobře.
Takže když já v jedné aplikaci, kterou píšu v Rustu, používám GTK, který se unsafe bloky jen hemží, tak to pro mě znamená, že nemám jistotu, že to za určitých blbých situací (protože bych ty funkce, které používají unsafe části použil nešťastně) nespadne, je to tak?
Tohle je pravda, a vůbec to nerozporuju.
A teď si představme, že bych tu mou aplikaci napsal v C, nebo nedejbože v C++. Byl bych na tom lépe?
Boli by ste na tom úplne rovnako. Aj v C++ nedefinované správanie v časti kódu spôsobuje neplatnosť celej aplikácie.
A nejde o to, že "protože bych ty funkce, které používají unsafe části použil nešťastně" ale o to, že samotné tie funkcie môžu byť napísané nešťastne a ich účinky sa môžu šíriť ďalej ako si myslíte.
Pokud poptávám jednodužší jazyk, tak pak jsou tvé námitky ok. Tímto procesem jsem si prošel a zvolil bych jazyk Lua.
Já poptávám jazyk, který mi ušetří práci. Který poskytne nějaké záruky.
Ve skutečnosti mluvím o reálném příběhu aplikace, na kterém se C++ ukázal v celé své nahé kráse jazyka úplně k ničemu. C je na tom o chloupek lepší, ale alespoň je jednodužší, jak říkáš.
Obávám se, že jsme se dostali do tradičního stavu Rust kritiků (ačkoliv původních argumentů jsem si všiml, a beru je v potaz): Rust není bezchybný, to nikdo netvrdí. Jen je prostě o tolik lepší jak psát to v C, a přináší to tolik výhod, že to stojí za to do toho přepisovat i docela slušně velké aplikace.
> C je na tom o chloupek lepší, ale alespoň je jednodužší, jak říkáš.
Přijde mi, že C je často použito ne zrovna vhodným způsobem. A mnoho problémů s C je jen důsledkem.
> Rust není bezchybný, to nikdo netvrdí. Jen je prostě o tolik lepší jak psát to v C, a přináší to tolik výhod, že to stojí za to do toho přepisovat i docela slušně velké aplikace.
Možná. Nicméně přijde mi, že z uživatelského hlediska kvalita programů v posledních letech spíše klesá. Takže nevím, jestli je zaručeně dobré řídit se posledními trendy.
To není o trendech.
C nabízí přehlednost, jinak neposkytuje vůbec žádné, slovy "vůbec žádné", záruky.
Rust je stále výborně přehledný, a nabízí více záruk jak debilní C#, nebo kreténská Java. (Mluvím o zárukách, ne o GC).
> Přijde mi, že C je často použito ne zrovna vhodným způsobem.
Ne.
Problém je v tom, že i když jsi ten nejlepší vývojář pod sluncem, tak tam furt _můžeš_ nasekat chyby. Což někteří (já) považují za neakceptovatelné.
Nemluvě o tom, že nemám ani špatné vývojáře, natož výborné.
>>>Rust je stále výborně přehledný, a nabízí více záruk jak debilní C#, nebo kreténská Java. (Mluvím o zárukách, ne o GC).
Keď sa v kreténskej Jave programuje funkcionálne a používajú sa immutables, veľmi pripomína Rust. Preto ako kreténskemu javistovi mi nerobí problém programovanie v Rust.
22. 2. 2025, 21:28 editováno autorem komentáře
> Problém je v tom, že i když jsi ten nejlepší vývojář pod sluncem, tak tam furt _můžeš_ nasekat chyby. Což někteří (já) považují za neakceptovatelné.
To mohu nasekat i v Rustu. Viz odkazy, které jsem posílal. A to byly chyby ze standardní knihovny, takže to byl kód, co psali experti (hádám). Jak by to napsal někdo, kdo pracuje v Rustu třeba jen jeden rok?
> Rust je stále výborně přehledný
To si právě nemyslím. Doložil jsem i příklady. Třeba duplikace kódu pro různé druhy referencí (to se týká i knihoven v safe Rustu), 2x delší kód pro vkládání do B-stromu.
Nebo utonutí v typových anotacích: Podobné věci v Rustu nejsou výjimka:
impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
Přičemž třeba v by v jednodušším jazyce stačilo, že implementujete metodu na HandleEdge<K, V>.
Nebo situace, kdy typy zaberou 3 řádky a implementace 1:
impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>>
where
A: 'static,
{
fn from(boxed: Box<T, A>) -> Self {
Box::into_pin(boxed)
}
}
> a nabízí více záruk jak debilní C#, nebo kreténská Java. (Mluvím o zárukách, ne o GC).
Jak v čem. Rust třeba nezaručí, že nemáte memory leaky. Což arena alokátor v jiných jazycích zaručí (místo leaků pak můžete mít use after free).
GC vám také dává záruky, nehrozí třeba cykly jako s Rc nebo Arc v Rustu. Takže nebudete leakovat tolik paměti. Díky GC máte v C# a Javě o dost jednodušší async kód. V novější Javě dokonce vypadá stejně jako sync kód.
> To mohu nasekat i v Rustu. ... Jak v čem. Rust třeba nezaručí, že nemáte memory leaky.
Tomu budou budoucí generace říkat Rustí klam: "0% záruk > 99% záruk".
> To si právě nemyslím.
Zde jsme v oblasti subjektivity. Psal jsem v mnoha jazycích. Pro mě Rust je fantazie. Samozřejmě, že by se mi líbilo, aby byl ještě víc stručnější a kdesicosi. Ale za tu cenu, je to nádhera.
> Rust třeba nezaručí, že nemáte memory leaky. Což arena alokátor v jiných jazycích zaručí (místo leaků pak můžete mít use after free).
Schodil jsem na memory leaku Javu i C#. Takže toto nežeru.
Každopádně zde se odkláníme od tématu. GC v této doméně nelze použít, tak jím nelze argumentovat.
impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
Já si tohle jenom půjčím pro okomentování něčeho, co se stalo v jednom programu v golangu.
Roky se mladí progs učí, že program má být přehledný, metody (funkce, procedury) krátké a správně pojmenované, globální proměnné se nemají používat. Což se naštěstí tak nějak dodržuje.
Potom někdo vymyslel anonymní funkce / lambdy / closures, asi proto, že se mu nechtělo fce pojmenovávat. A současně to má tu "výhodu", že málokoho překvapí, že se uvnitř bloku anonymní fce pracuje s proměnnými pocházející mimo tento blog. Takže se jedním vrzem odstranilo pojmenování a nepoužívání globálních proměnných.
Potom stačí jedno malé opomenutí jedné vlastnosti řídící proměnné cyklu for. Tedy, že se v těle for nevytváří kopie hodnoty této proměnné, ale předává se jenom reference (což platí pro více jazyků). Tohle běžně vůbec nevadí, protože slušně napsaná smyčka for je většinou dead simple a předání hodnoty do funkce v golangu automaticky vytvoří kopii.
Jenže, pokud se někdo rozhodně v jednom cyklu for použít veškerou syntaxe golangu (která je ze zde diskutovaných jazyků nejjednodušší), tedy gorutiny, anonymní fce a zapomene na vlastnost for, tak je malér.
Tohle se stalo v LetsEncrypt, to je jediný příklad, který je znám a to díky tomu, že je to opensource. Autoři golangu změnu implementace for cyklu testovali na veškerém dostupném kódu a nikde nenašli další případ. Vlastně jenom proto, že ostatní progs nejsou tak šílení, aby do jednoho řádku narvali veškerou znalost prog jazyka.
A to je vlastně docela smutné a současně velké varování. Že i v programu, na který spoléhá možná většina webových serverů na světě (tohle nevím, ale LE certifikátů není málo) si ani review neřeklo "hele kámo, brzdi, napiš to pořádně jako prvňáček, fakt není potřeba použít všechnu znalost na 5 řádcích" a současně ani člověka na review nenapadlo se na to podívat "hele, nemáš tady kopii hodnoty, není to náhodou špatně?".
A tak si říkám, jestli syntaxe Rustu a C++ (template) typu "hmmm, který symbol z unicode jsme ještě na nic nepoužili?" je opravdu tím nejvhodnějším způsobem, jak programovat. Prostě různé otazníky, vykřičníky, příliš ukecané template (nekonečně dlouhé řádky), do toho všechny ostatní vlastnosti jazyka, tohle fakt člověk v aktivní paměti neudrží a jestli fakt není lepší s tímhle brzdit.
>>> Osobně mi přijde že Rust vznikl naopak jako snaha jít proti trendům o krok zpátky, vrátit se k základům a udělat je líp.
Not true, Rust je veľmi trendy. Roku pána cca niekedy pred viac ako 10 rokmi som bol na konferencii ECOOP. Padli tam rôzne kritiky OOP vyzerá, že pán, ktorý vymyslel Rust, počúval. Asi po tých konferenciach sám chodil. Jeho šéf bol naviac Brendan Eich, autor javascripu.
22. 2. 2025, 23:01 editováno autorem komentáře
> nepadá s unsafe kódem hlavní výhoda Rustu oproti C?
Unsafe kód je potenciální problém, ale je-li užit s mírou, jde o problém, který máme vlastně v každém jazyce. Napište v libovolném memory-safe jazyce hello world. Když budeme dostatečně pátrat, dříve později narazíme na to, že se v implementaci budou používat různé unsafe věci. U Rustu to je vlastně stejně.
Ano. Jenže v jiných jazycích je jejich safe část flexibilnější, takže si často vystačíte se standardní knihovnou a sám už unsafe kód psát nemusíte. Jenže v Rustu, když třeba chcete v BTreeMap použít uspořádání, které závisí na lokální proměnné (např. nějaká tabulka, co udává uspořádání), tak musíte použít unsafe kód, pokud nechcete měnit typ, co v BTreeMap ukládáte. Důvodem je, že instance traitů nemohou záviset na lokálních proměnných.
Takže i na triviální problémy, co v jiných jazycích ani nejsou, potřebujete unsafe.
Nebo... hledal jsem bezzámkovou frontu a knihovny, co jsem našel, obsahovaly unsafe kód. První článek, jak to implementovat v Rustu, co mi Google najde, opět obsahuje unsafe.
Bohužel, v Rustu i u malých a jednoduchých programů narážím na to, že to bez unsafe nejde. Nedovedu si tedy představit, jak se unsafe jádro vyhne. A pokud se mu nevyhne, tak tam nejspíš bude víc chyb než v C, protože psát unsafe v Rustu je náročnější než v C - věci, co jsou v C ok, jsou v Rustu nedefinované chování.
> věci, co jsou v C ok, jsou v Rustu nedefinované chování.
Které další? Jediný dosavadní příklad, předpoklad že nedochází k aliasingu, Rust neuplatňuje na raw pointery, takže to bylo nepochopení jazyka z tvé strany.
Věci které v Rustu potřebují unsafe jsou reálně fakt složité udělat dobře i v C. Jediný rozdíl je, že C umožňuje potenciální problémy snáz ignorovat.
> Věci které v Rustu potřebují unsafe jsou reálně fakt složité udělat dobře i v C.
Umožnit BTreeMap, aby brala porovnávací funkci by nebylo tak obtížné. Bohužel Rust se rozhodl pro méně flexibilní design, kdy to bere globální instanci traitu, která nemůže záviset na lokální proměnné.
Stejně tak není tak složité do C přepsat implementaci datové struktury z nějaké knihy nebo článku. Jenže do safe Rustu to často nejde, protože vám brání typový systém.
Často Rust totiž dělá z triviálních věcí věci dost složité, i když by to nebylo třeba. Viz třeba zmíněný node.rs z BTreeMap, který se přepisem do C zmenší více než o polovinu.
> Umožnit BTreeMap, aby brala porovnávací funkci by nebylo tak obtížné
Zrovna nedávno jsem řešila to samé pro btreeset. Dospěla jsem k závěru, že pokud chci pro daný typ nějaký specifický ordering v btreeset, asi ho chci všude, jinak by se choval nekonzistentně. Stačilo vyrobit typ který obsahoval inner value a referenci na ordering table podle které se mají prvky řadit, a implementovat Ord pro daný typ. Bylo by jednodušší mít custom ordering funkci pro btreeset? Asi ano. Porušovalo by to principle of least astonishment, protože by se daný typ řadil různě v různých kontextech? Taky ano. Tohle mi přijde jako lepší řešení (a bez unsafe)
> Stejně tak není tak složité do C přepsat implementaci datové struktury z nějaké knihy nebo článku. Jenže do safe Rustu to často nejde, protože vám brání typový systém.
99% času v tom brání z dobrého důvodu. Napsat správně třeba double LinkedList není úplně triviální, a spousta "implementací v nějakém článku" blbě.
> Dospěla jsem k závěru, že pokud chci pro daný typ nějaký specifický ordering v btreeset, asi ho chci všude, jinak by se choval nekonzistentně. Stačilo vyrobit typ který obsahoval inner value a referenci na ordering
Jakoze v kazde hodnote daneho typu bude reference na tabulku? To mi prislo jako plytvani - mel jsem pres 500 milionu hodnot, takze bych 4 GB pameti vyhodil kvuli spatne udelane standardni knihovne.
Ještě mě napadá, obecně považuju static za antipattern ve většině případů, ale pokud je ordering prvků nějakého typu založený na nějaké globálně uznávané třídicí tabulce, asi nevidím problém mít ji jako static. Ale uznávám že to je celkem nedostatek, naštěstí to není potřeba na kterou reálně narážím.
Což je samozřejmě za požadavku "nesáhnu na nic mimo std", jinak https://docs.rs/indexmap/latest/indexmap/
> Jenže do safe Rustu to často nejde, protože vám brání typový systém
A to je dobře nebo špatně?
On unsafe Rust je naprosto geniální koncept (geniální, ne originální, má ho každý druhý jazyk). Prostě někdy není ekonomické, případně ani možné, některé věci napsat v Rustu, a tak je k tomu k dispozici toto.
> který se přepisem do C zmenší více než o polovinu.
Za jakou cenu?
>> který se přepisem do C zmenší více než o polovinu.
> Za jakou cenu?
Je to přehlednější a rovněž unsafe jako v Rustu. Jen není potřeba dodržovat tolik invariantů. Takže ten unsafe kód snadno můžete použít, zatímco v Rustu je těžké ho použít, aniž byste porušil nějaké invarianty. Ve výsledku negativa nejsou žádná.
>> tak tam nejspíš bude víc chyb než v C
> A nebo spíše ne.
Bohužel spíše ano, proto má Rust Miri, protože hledat ty chyby ručně je těžší než v C. Viz třeba When Zig is safer and faster than Rust
What. Hledat memory safety issues ručně v čemkoliv větším v C/C++ bez toolingu fakt nejde, proto existuje valgrind a řada sanitizerů, ideálně ještě fuzzer. Poukazovat na to, že v případě unsafe (který fakt není potřeba pro velkou část projektů) je fajn použít miri a uvádět to jako nevýhodu proti C je docela chutzpah, ne?
Existencia miri môže byť nevýhodou iba pre tých, krorí predpokladajú alebo očakávajú, že všetky problémy s programom dokáže alebo by mal odhlaliť prekladač. Ako jediný potrebný nástroj. Pre všetkých ostatných je miri iba ďalší dodatočný nástroj. A keď už je schodná potreba jedného dodatočného nástroja, tak nie je dôvod, aby potreba viacerých dodatočných nástrojov, v iných jazykoch, bola neschodná.