Původně jsem si myslel, že když už udělaji nový "bezpečnější" jazyk, bude snaha omezit programátora syntakticky tak, aby nemohl příliš "prasit" a zapsat vše pouze jedním - a tím správným způsobem, ale tak to jak si pročítám seriál o Rustu (podle mě bohužel) není. Objevuje se tady "takto je to idimaticky správně", lze to "naprasit" i takto... Velmi to připomíná současné C++, ano pokud to budete "psát idiomaticky správně" eliminujete hromadu možných bezpečnostních problémů (http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines), ale můžete to psát i jinak a ještě hůře... (ano C++ je v tom dále z toho důvodu že je straší). S posledními aktualizacemi C++11..17 bych řekl, že se C++ dostává někam na úroveň Rustu i z hlediska bezpečnosti zápisu (jen to stále lze "naprasit" i dalšími a mnohem horšími způsoby).
Pokud chceš jazyk, který tě omezuje v tom, co se jak má napsat a použít, podívej se spíš na golang. Rust má jinou filosofii a není tak striktní. V Rustu neexistuje "ta jediná správná cesta", jak by se něco mělo dělat. Je to dáno taky tím, že se snaží být multiparadigmatický, je imperativní, ale současně můžeš používat i funkcionální prvky. C++ se nikdy nedostane co se týká bezpečnosti na úroveň Rustu, protože není memory safe.
Bohužel to že je Rust memory-safe je lež! :-( Bylo tomu tak, ale z důvodu výkonu odstranili morestack (s tím že správné/lepší řešení je -fstck-check). Jenže v LLVM je -fstack-check no-op, není implementovaný a kdoví kdy bude. Jediná platforma kde je implementovaný jsou Windows.
Tzn. Rust je memory-safe pouze na Windows, na všech ostatních platformách _není_ memory-safe.
Viz diskuze u pull requestu: Remove morestack support #27338
Nesegfaultuje, pada na stack overflow (a jeste kompilator docela slusne drzkuje):
---- sf.rs:
fn r(a: &[i8]){
let a: [i8; 8193] = [0; 8193];
r(&a);
}
fn main()
{
let a: [i8; 8193] = [0; 8193];
r(&a);
}
---- kompilace:
rustc sf.rs
warning: unused variable: `a`, #[warn(unused_variables)] on by default
--> sf.rs:1:6
|
1 | fn r(a: &[i8]){
| ^
warning: function cannot return without recurring, #[warn(unconditional_recursion)] on by default
--> sf.rs:1:1
|
1 | fn r(a: &[i8]){
| ^
|
note: recursive call site
--> sf.rs:3:5
|
3 | r(&a);
| ^^^^^
= help: a `loop` may express intention better if this is on purpose
---- spusteni:
./sf
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
Aborted (core dumped)
Zkuste to spustis vícekrát. Bez morestack (a implementovaných stack probes, které by ho měly nahradit) je to více méně náhodné, někdy to Rust chytí a někdy ne. Prostě dobrovolně obětovali memory-safety na všech platformách kromě Windows, jen aby získali pár procent výkonu navíc :-(
Vcera jsem to zkousel, fakt to obcas hlasi segfault. Otazka ale je, co se ve skutecnosti deje. Mel jsem za to, ze kdyz se tohle stane, Rust (jiny jazyk kompilovany do strojaku) se snazi zapsat, kam uz nema (mimo vyhrazeny stack) a system proces sejme. V lepsim pripade to runtime stihne detekovat a vypise korektni stack overflow (ano, bylo by super, kdyby to spolehlive fungovalo), ale k zadne nepredvidatelne akci (krome padu) by to vest nemelo. Pletu se?
Priznam se, ze Rust neznam. V adresnim prostoru procesu na Linuxu, jsou zasobniky polozene za sebou. Tzn. tam kde konci prvni stack, zacina stack dalsiho threadu. Mezi nimi je jedna zamcena stranka, na kterou nesmite sahnout, jinak dojde k segfaultu. Melo by to pomoct vyresit situace kdy stack overflow, prepise stack druheho vlakna. Takove chyby by se hodne blbe ladily.
Pokud ale alokujete pamet na zasovnibku po prilis velkych kusech, muze se vam stat, ze tu zamcenou stranku preskocite a druhemu vlaknu stack stejne prepisete.
Ale samozřejmě nikdo nikomu nebrání používat namísto Rustu Haskell nebo Ocaml.
Bohužel v obou jazycích existují a poměrně často se v běžných knihovnách a programech i používají funkce, kterými lze o memory safety přijít. (Nemluvím o FFI.)
Dokud mi někdo neukáže praktický a smysluplný příklad zneužitelnosti, považuju to za hnidopišství.
Já tomu říkám lhaní. Píší guaranteed memory safety, a to nejenže na to nemají žádný formální důkaz, ale dokonce vědí, že opak je pravdou.
Celkově je těch omezení dost. Nějaké idomy tam pochopitelně jsou (třeba psát match místo if), ale Rust omezuje hodně.
No a navíc - spousta legálních věcí při kompilaci zahlásí warning, že "takhle raději ne". A warningy jsou on by default.
A jako bonus je tu formatter, který udržuje i jednotné formátování mezi projekty.
Příklad pár warningů z jednoho mého malého narychlo napsaného prográmku:
warning: unnecessary parentheses around assigned value, #[warn(unused_parens)] on by default
warning: unnecessary parentheses around `if` condition, #[warn(unused_parens)] on by default
warning: unused import, #[warn(unused_imports)] on by default
warning: unused variable: `platform`, #[warn(unused_variables)] on by default
warning: function `kupfuCheckSum` should have a snake case name such as `kupfu_check_sum`, #[warn(non_snake_case)] on by default