A Rust-ban való Linux kernel fejlesztés támogatása

Címkék
Szabadon olvashatóvá vált a Linux Weekly News augusztus 31-én megjelent, eddig fizetős cikke, ami összeszedi az elérhető infókat a $title témában:
The Rust programming language has long aimed to be a suitable replacement for C in operating-system kernel development. As Rust has matured, many developers have expressed growing interest in using it in the Linux kernel. At the 2020 (virtual) Linux Plumbers Conference, the LLVM microconference track hosted a session on open questions about and obstacles to accepting Rust upstream in the Linux kernel. The interest in this topic can be seen in the fact that this was the single most heavily attended session at the 2020 event.

A teljes cikk elolvasható itt.

Hozzászólások

Szerkesztve: 2020. 09. 01., k - 10:09

TL;DR:

  • Biztonság: focused on security concerns, citing work showing that around two-thirds of the kernel vulnerabilities that were assigned CVEs in both Android and Ubuntu stem from memory-safety issues. Rust, in principle, can completely avoid this error class via safer APIs enabled by its type system and borrow checker.
  • Linus és a többi core kernelkarbantartó nyitott rá - Linus Torvalds and other core kernel maintainers have expressed openness in principle to supporting kernel development in Rust
  • Nem a kernel újraírásáról van szó, hanem a jövőbeli fejlesztésekről - they are not proposing a rewrite of the Linux kernel into Rust; they are focused only on moving toward a world where new code may be written in Rust
  • Jól együttműködik a C kóddal - Rust has good support for interoperating with C code, including support for both calling functions using the C ABI and for defining functions with C-compatible ABIs that can be called from C
  • Vannak még megoldásra váró kihívások - the session revealed a handful of open challenges. For example, Linux makes heavy use of preprocessor macros and inline functions, which aren't easily supported by bindgen and Rust's foreign-function interface.
  • Kényes kérdés még az architektúrák támogatása - At present, the only mature Rust implementation is the rustc compiler, which emits code via LLVM. The Linux kernel supports a wide range of architectures, several of which have no available LLVM backend. For a few others, an LLVM backend exists, but rustc does not yet support that backend. The presenters wanted to understand whether full architecture support was a blocker to enabling Rust in the kernel.
  • Az ABI-kompatibilitás probléma - Gaynor also asked for advice on a question of ABI compatibility. Since Rust is (currently) compiled via LLVM, and the kernel is most commonly built with GCC, linking Rust code into the kernel may mean mixing code emitted by GCC and LLVM. Even though LLVM aims to be ABI-compatible with GCC, there has been some pushback based on concerns that this strategy created a risk of subtle ABI incompatibilities. The presenters wondered whether the kernel community would prefer to limit Rust support to kernels built with Clang in order to ensure compatibility.

trey @ gépház

Tehát röviden:

Fontolják a Rust behozását, mert így rengeteg olyan hibafaktor kivédhető, ami a jelenlegi kernel CVE-k kétharmadát adják, de nincs még kész és használható megoldás arra, hogy implementálják, így a jelenlegi megoldások pont a Rust biztonságát dobják félre.

Illetve egy olyan nyelvről van most szó ami rengeteg olyan platformon nem használható, amit a kernel jelenleg támogat.

 

Eddig jók a kilátások!

"Errors are red
My screen in blue
Someone help me
I've deleted Sys32"

Tud valaki esetleg arról, hogy szélesebb körben is vizsgálják más nyelvek bevonását, vagy csak a Rustot próbálják beszuszakolni. Születtek az elmúlt 10-20 évben más modern nyelvek is (D, Nim, Go, Swift, ...) rendszerprogramozásra, érdekes lenne egy értelmes szakmai összevetés köztük a kernel fejélesztés szempontjából.

Tudtommal nincs ilyesmi törekvés egyik nyelvre sem. A Rust jó pozícióból indul, mert nagyon felkapott nyelv és biztonságos (jó kezekben). Régebben akarták behozni a C++-t, de azt Torvalds elvből elutasította.

"Errors are red
My screen in blue
Someone help me
I've deleted Sys32"

Valahogy a "hypeoltság" nem tartozik a kedvenc szakmai érveim közé. :-) Ezért lnne jó egy tényleges szakmai alapú összevetés. A C++ sajnos a legjobb indulattal sem mondható modern nyelvnek, még az újabb szabványverziókkal együtt sem. Ezért sem vettem ebbe a körbe.

Tudom, hogy korábban sportoltak rajta, hogy a C++-t vagy legalább a fordítót használják a kernelfejlesztésben. De végül a fordítót sem sikerült, mert iszonyat mennyiségű fordítási anomália volt.

Disclaimer: c++-t programozok penzert, tehat nem vagyok elfogulatlan egyaltalan.

Ha csak a feature-oket nezem a c++ is meglepoen modern nyelv. Mas kerdes, hogy a nyelv tervezesi alapelvei kozul melyik az, ami fontos es relevans ma is. Egyetertek azzal is, hogy Linus nem volt tulzottan motivalt abban, hogy a kernelt megnyissa a c++ fejlesztok fele.

De ha mar bashingeljuk a prognyelveket, akkor nyilvanvaloan nem csak a c++ hazanal van szemet:

1. A Go-nak pl. garbage collectora van. A felreertes onnan ered, hogy a Go-t rendszerprogramozasi nyelvnek szantak, de nem abban az ertelemben, hogy irjunk benne kernelt, hanem mondjuk irjunk benne szerveralkalmazasokat, halozati szolgaltatasokat (docker-t, IPFS-t, VPN klienst, adatbazis szervert stb. stb.). Szerintem a c++ is itt muzsikal a legjobban.

2. A Nim eleg partizan dolog. Community es nemi intezmenyi tamogatas nem artana moge. Marmint pl. gondolom egy magyar NIM konferenciara nem kellene kiberelni a Millenarist. Addig arrol beszelunk, hogy valakiknek pokolian sokat kellene dolgoznia, azert, hogy annak a 10 NIM fejlesztonek meglegyen a teoretikus lehetosege, hogy irjon egy kernelmodult. Egyszeruen nem lenne gazdasagos.

3. A Swift-nel szerintem soha nem is volt fokusz az, hogy ilyesmire hasznaljak. Vegignezve a feature listat (marmint kernelfejlesztesi igenyek alapjan), szerintem minden, amit tud a Swift, tudja a Rust is, csak jobban. Nem azt mondom, hogy a Swift szarabb, mint a Rust, mert amint arrol van szo, hogy mobilappot akarok csinalni iOS-re, egybol kivilagosodik az eg.

A Rust ebbol a szempontbol talan tenyleg a legjobb valasztas lehet, *ha* ugy dontottunk, hogy megprobaljuk ledobni a c-t mint legacyt. Strategiailag szerintem nem a legokosabb dontes. Ha engem kerdeznek, akkor irjanak egy kernelt Rust-ban (a la Redox), es mutassak meg, hogy a Rust velelmezett elonyei mennyivel faszabb eredmenyeket hoz. Bar a Rust tenyleg nagyon jo dolog, jot mosolygok, amikor azt latom, hogy a crate-ek egy jelentos resze bewrappel unsafe lib-eket (libmysqlclient, rocksdb, libpng, libpg, sqlite, curl, libopenssl (!!!) lehetne sorolni a vegtelensegig). Kicsit arrol van szo, hogyha irsz egy 5000 soros Rust service-t, akkor meg ott fog ketyegni alatta 100000 sornyi c/c++ kod es azt probaljuk allitani, hogy ez igy teljesen biztonsagos?

 

Ettol fuggetlenul en kivancsi vagyok ra, hogy mi lesz a kimenetele dolgoknak ezen a teren es kicsit drukkolok is a Rust-nak.

java, python, perl is mind ugy kezdte, hogy a c lib-eket wrapeltek, mielott pure-X lib lett volna. A nativ client lib ugyanis egy halom melo, es ha gyorsan kell valami mukodo, akkor ez marad.

A crate leirasaban benne van, hogy mi a helyzet.

Amugy pl. openssl helyett van mar rustls, sajat kezuleg is konvertaltam a ketto kozott. Azt nem akarod tudni, mekkora szopas nem nativ lib-eket static-ba forditani a scratch docker image-hez.

Elvből elutasítás tudtommal csak az utóbbi években volt, arra hivatkozva hogy régen konkrétan megpróbálták.

És szerintem teljesen igaza is volt abban, amit leírt.

Én nem szidom a C++-t, mert kb. az egyetlen kiforrott magas szintű nyelv, ahol a teljesítmény is számít, és C++-ban lehet szép tiszta kódot is írni. De nekem mindig az jött le, hogy amikor C-vel elkezdik keverni, na akkor elszabadul a pokol. Illetve az embernek nagyon jól előre ki kell találnia, hogy hogyan akar programozni, mert a C++ az tényleg multi-paradigm, és ezeket sem feltétlenül jó keverni.

Sajnálatos, hogy az ipar egyik meghatározó szakembere ilyen kevés szakmaiságot tudott ebben a kirohanásában felmutatni. Pedig vannak érvek a C++ ellen, de itt az érvelés elmaradt, csak egy rakat frusztráció tört fel. Az STL-t és a Boost-ot összemosni magával a nyelvvel pedig tényleg harmat gyenge dolog.

A C++ nem egy problémamentes nyelv, sőt, de támogatja nyelvi szinten az OO paradigmát, amit a C nem, és ez bizony még a kernelfejlesztésben is hasznos lehet. Igen lehet enélkül is, de ez nem jelenti azt, hogy az OO paradigma vagy annak a C++ implementációja ne lenne alkalmas kernelfejlesztésre. Mint minden nyelvhez, így a C-hez és a C++-hoz is szükséges egy erős kódolási szabályrendszer, és akkor bizonyos problémák elég jól elkerülhetőek. Engngem egyébként mindig meglep ez a heves C vs. C++ flame. Mindkét nyelv meglehetősen hiányos, ha a mai modern nyelvekkel hasonlítjuk össze, az erejüket inkább csak az elterjedtségük adja. Pont ezért érdekes az a kérdésfelvetés, hogy képes-e valamelyik modern, rendszerprogramozásra szánt nyelv lassan kiváltani ezt a két itt maradt relikviát.

Ezért is lenne érdekes egy katalógusműveltségen túlmutató, Linus-féle furzstrációktól mentes, szakmai elemzés, áttekintés.

A fv. pointeres eset kb. ugyanúgy működik, mint a C++-ban a virtual metódusok. Annyira nem hatékony (bár a mai világban ezt már tényleg fel se vegyük). Egyébként ez a szebbik módszer.
Nézd meg, hogy a glib hogy csinál OOP-t C-ben. Na az hányás, és nem értem minek kellett erőltetni. C-ben nagyon jól lehet procedurálisan programozni, ehhez kellett volna az adatstruktúrát igazítani, nem pedig az objektum-orientáltságot a C-re erőltetni.

"C-ben is lehet OO paradigmával programozni, nem kell ahhoz nyelvi támogatás"

Igen, lehet. De ki tenne ilyet önszántából? A kérdés költői, tudom, hogy vannak ilyen projektek. Csak azon gondolkozom, hogy milyen megalapozott szakmai érv szól mellette, ahelyet, hogy C++-t használna.

Ugyanis nem csak a függvény virualizációt kell megoldani, hanem az adatstrukturák példanyosítását is. C++-ban ezt mind megoldja a fordító, a programozó meg foglalkozhat a feladattal, nem pedig a nyelv alapszíntű átbuherálásaval kell kinlódnia.

nem pedig a nyelv alapszíntű átbuherálásaval kell kinlódnia.

ott a pont. mert alapvetoen mindenre lehet seged-fuggvenyeket csinalni, es igenis lehet C-ben is java-szintu kodot irni, csak lib kerdese.

Az egyetlen kerdes, hogy praktikus-e.

Mondjuk tudok olyan esetet elkepzelni, ahol igen (pl. mert megrendelo kikototte, hogy c kell neki).

Deugye erted, hogy ezt mint kernelfejleszto irja emberunk. Es nem lehet vele elegge egyeterteni. En sok-sok ev c++ programozassal a hatam mogott (de elismerve, hogy a kernelhez csak nagyon picit ertek) nemigen latom, hogy miert lenne jo c++-t hasznalni a kernelben.

Csak ha mondjuk csak egy kicsit is elkezdesz feljebb lepdelni az absztrakcios szinteken (tehat nem kernelt irsz, hanem mondjuk a egy message-broker-t vagy mondjuk egy VPN szervert), akkor hirtelen elkezdhet hasznos lenni a c++ is. Nekem konkret tapasztalatom, hogy egy viszonylag nagy eredetileg c-ben fejlesztett elosztott rendszer komponenseit irtuk at c++-ra (telkos teruleten) es ott feature es performance parity-t ertunk el ugy, hogy a c++ kodsorok szama 60-70%-al lett kevesebb, mint a c-nel volt es sok helyen sikerult a fejlesztesi hibalehetosegeket eliminalni (tehat karbantarthatobb, konnyebben modosithato lett a rendszer). Ilyen szamokra azert lehet talalni fizetokepes keresletet :). 

Nem volt elbaszva, az egyik legszebben, legjobban, dokumentaltan megirt kod volt, amit eletemben lattam. Elkepesztoen jol hasznalta az eroforrasokat, a stabilitasarol meg sokat elmond, hogy voltak olyan szerver processzek az elosztott rendszerben, amiknek egyeves felett volt az uptime-ja, mindezt ugy, hogy naponta legalabb 60000 teszthivast (SIP/ISDN/POTS) bonyolitott. De az is lehet, hogy te latatlanban megmondod minden kodrol, hogy milyen minosegu, lol. Indits ra vallalkozast, milliokat fogsz kaszalni kemeny valutaban. Vagy nem.

Egyszeruen ha valaki tenyleg jol erti es hasznalja a modern c++-t, akkor bizonyos dolgokat ennyivel kompaktabban lehet megcsinalni. Dehat errol szol az absztrakcio. *Ha* van ertelme a magasabb absztrakcios szintnek, akkor eppen az a lenyeg, hogy kepes nagysagrendileg tomorebben megfogni ugyanazokat a koncepciokat, mint egy alacsonyabb szintu nyelv. Ha ez nem sikerul, akkor valoszinuleg az alacsonyabb absztrakcios szint a jobb valasztas. Jelen esetben pl. a Linux kernel szerintem nem nyerne sokat vele, ha c++-ban dolgoznanak vele, viszont eleg sok komplexitast behuznanak (c++ komplexitas vs. c komplexitas, c++ ABI komplexitas vs. c ABI komplexitas, etc. etc.).

Kernelt én sem fejlesztettem még, de firmware fejlesztésnél nagyon sok feladatot sokkal jobban lehetett C++-ban megoldani. Egyszerűen ismerni kell a nyelvet. Igen ez nem alapfeladat. De tapasztalt és jól felkészült fejlesztőkkel (amilyennek én a Linux kernel fejlesztőit gondolnám) illetve megfelelő kódolási szabályokkal a C++ semmivel nem rosszabb a C-nél, viszont bizonyos feladatoknál pedig jelentősen jobb. Szerintem kezdők, vagy nem jól felkészült programozók C-ben sem tudnak kernelt fejleszteni.

*Ha* van ertelme a magasabb absztrakcios szintnek, akkor eppen az a lenyeg, hogy kepes nagysagrendileg tomorebben megfogni ugyanazokat a koncepciokat,a.k.a. good code vs bad code.

Hiaba van szepen dokumentalva es tesztelve egy kod, ha a rossz design miatt igazabol sokkal tomorebben lehet megirni, attol az meg nem jo kod. Igen, nagyon is pozitiv a tiszta, tesztelt kod, es production-ban tokeletesen mukodik is. De a szoftverfejlesztes koltsege tipikusan 80% maintenance. Most errol ne vitatkozzunk, hogy hany szazalek, mert igen, biztos van projekt, amit megirtak egyszer es 20 evig hozza se nyult senki, de nem ez a tipikus.

Ha egy szoftver haromszor akkora, akkor ertelemszeruen a karbantartasi koltsege is nagyobb lesz. Es errol az oldalarol nezve nagyon is rossz kod.

Na persze ebbe is bele lehet kotni, hogy egyaltalan nem biztos ez se, mert ha az eredeti fejlesztoje csinalja a karbantartast es nem csinal 30 kulonbozo fejleszto spagettit a code base-bol, akkor ez sem igaz, de megint csak, nem ez a tipikus. A jellemzo az, hogy egy code base keresztulmegy minimum 2-3 team-en, mire kidobjak, es kellemesen osszekokanyolja mindegyik egy picit. Ott pedig mar igenis sokat szamit, hogy mekkora a spagettive varazsolt kod merete.

Nem volt magikus a dolog. Atirtunk 1-2 modult (ez kezdetben docogve ment, mert c++11-el kezdtunk egybol gcc 4.6 idejen, mi is tanultuk az uj szabvanyt, nem is volt meg vegleges, a fordito tamogatas meg nem volt teljes), es latszott a kulonbseg (c++-al kevesebb volt a kodban elrejtett implicit tudas, es kompaktabb lett minden). Onnan meg mar csak azon kellett vivodni, hogy a migraciot lehet-e majd gyorsitani, tehat ha az elejen egy atlagos modult mondjuk 4 het alatt irtuk at, mire jo lett, ezt le lehet-e vinni 2 hetre, vagy 1 hetre. Nyilvan tanul az ember es mar nem lovi annyiszor magat labon.

Ket dolog arnyalja a kepet:

1. A cucc alapbol jol volt megirva c-ben. Tehat nem egy hulladek, millio soros spagettit kellett helyrepofozni. Jo volt a szoftverarchitektura es szepen is volt a kod megirva. Tehat lehetett dekompozicioval elni es modulonkent haladni. Ez a jo iranyba tolta a dolgokat (tervezhetobb volt a dolog es lehetett inkrementalisan haladni, nem egy ugras az ismeretlenbe).

2. Annak az allapotnak azert vannak hatranyai, amikor a c++ es c megkozelites egyszerre letezik a kodban. Pl. nonblocking IO-hoz libevent-et kellene hasznalni c-bol, asio-t c++-bol. Ami rogton megvaltoztatja a szalkezelesi strategiat, mert nyilvan egy szal nem kepes futtatni mindket eventloopot. Legtobb internal API eseteben vagy ragaszkodsz a c-hez, es akkor a c++ elonyeit nem tudod maradektalanul kiaknazni, vagy meno c++-os internal API-t definialsz, de akkor legacy wrappert kell adni hozza, hogy tudjak hasznalni a c-s modulok. Ez nyilvan extra koltsegkent jelenik meg.

A Magyarorszagon elterjedt 10 soros piros/zold mezos excelen kivul boldogulni keptelen szellemi kispalyas management-ek altalaban nem partnerek az ilyesmiben, mert sem az IT tudasuk sem a kockazatkezelo kepesseguk nincs meg hozza, ellenben a seggek vedese az nagyon tud menni. Nekem szerencsem volt, mert az en megrendelom ertette a dolgat es az uzleti/kockazati oldalat is jol kezelte a dolgoknak. Jo penzt kerestunk, sokat tanultunk es a cucc is jo lett nagyon :).

Első körben tehát ezek a nyelvek jöhetnek szóba. Tök jó.

Linux kernelnél szempont, hogy ne GC-re támaszkodjon alapból a memóriafelszabadítása. Kérdés az, hogy ez mennyire valós szempont?
Talán ebből látszik időkritikus ütemezőben való használatkor néhány hátulütője: https://dlang.org/spec/garbage.html#how_gc_works
A fenti nyelvekből a GC alapú automata memóriamenedzsment dobva Linux kernel esetén, ugyanakkor legyen biztonságos a memóriakezelése.
Nézzük, hogy mi maradt.

GC-t felejtsük már el! Ebből a szempontból a C++-ban (meg ahol van) a RAII jobb, teljesen determinisztikus. Pont ugyanazt csinálja, mint amit kézzel csinálnál C-ben, csak mindig lefut, nem lehet elrontani.

Más kérdés, hogy mindenhova nem egyszerű beilleszteni, de kernel kódba, ahol nem kell annyi dinamikus adatstruktúra, pont megfelel.

Állítólag a Microsoft a Qbasic nyelvet támogatná, a Borland pedig a 16 bites Turbo Pascalt. Komolyra fordítva a szót: egy új nyelv bevonása a kernel fordítása nagyon sok, jelenleg nem létező problémát, feladatot szülne. Nyilván vannak előnyök, de mi lesz azokkal a platformokkal, amiket a Rust nem támogat? Én inkább valahogy AI-val vagy bármilyen automatizálással, ahogy már most is nézik a kernelt algoritmusok, azt erősíteném, hogy a leggyakoribb hibákat jelezze valahogy. Különböző CPU-t és változatokat szimulálva, automatizált tesztelést, bármi olyasmivel javítani a jelenlegi fejlesztést.

Nem ide tartozik, de egyre nagyobb a kernel, ahogy egyre nagyobb a böngésző program is, jó lenne legalább 2 változat ezekből: az alap, tényleg csak ami szükséges, és a mostani, funkciókkal gazdag változat. Aki nem használja a cloud alapú felhő user profil kezelést, meg sok mindent, annak jobb lenne, ha nem lenne a kódban.

Sakk-matt,
KaTT :)

Szerkesztve: 2020. 09. 02., sze - 01:18

Rust hatalmas hatulutoje a meredek learning curve. Plane a C-hez kepest. Ugye 2 hetnyi C tanulas utan mar akar a kernel kodot is olvashatja az ember. 2 hetnyi rust utan mar erted, miert van annyi kerdes a stackoverflow-n. ;)

Ami iszonyatosan megneheziti a fejlesztest, az az, hogy statikus typing van ugyan, de a fordito implicit koveti a tipusokat, vagyis nem kell megadni kezzel a tipust, okos compiler kitalalja neked (tm). Amit aztan a lib-keszitok ki is hasznalnak, es olyanra epitik meg a lib-eket, hogy masszivan fuggnek attol, hogy egy adott modon csurd-csavard a kodot. Ha nem ugy teszed, szetesik az egesz, a fordito meg valami teljesen zagyva hibauzenetet ad (siman fel kepernyonyi tipushiba terminalon), amit szinte lehetetlen lenyomozni. Foleg a nagyon magas szintu lib-eknel vannak ezek, mint pl. hyper rest lookup megspekelve json deser-rel. Gyakorlatilag jopar nap, mire az ember kiismer egy library-t es tenyleg (alapszinten) el tudja hasznalni. Viszonyitaskeppen, es java/kotlin-ban kb. egy-ket ora.

Hasonlo gyilkos az implicit conversion. Elmeletileg a fordito kitalalja, hogy hogyan tudja az egyik tipust a masikra konvertalni, de pl. csak akkor, ha a konverzio fuggveny importalva van (!!!). Es nem mindig megy az sem. Gyakran sokaig tart, mire rajon az ember, hogy a 'foobar("10.0.0.1".parse())' miert mukodik, maskor meg miert nem.

Szinten gond, hogy nincs normalis fejlesztoi kornyezet. Persze, rust language server es tsai, de az egy modern platform kenyelmehez szokott dev-nek durvan fapados, kb. 20 evet vissza az idoben. Ami mukodott, az a clion volt, annak is csak a legujabb verzioi, de az meg penzes (cegunk vett par licenszet).

A borrow checker szinten erdekes dolgokat tud eredmenyezni, es amikor egy sima builder pattern-t csinalni egy napig tart eloszor, az ember a hajat tudja tepni. Szerencsere mostanra van egy par jo guide, meg best practice, hogy mit hogyan erdemes. De spec. a borrow checker azt kell mondjam, nagyon jo - mar tobbszor is belefutottam, hogy "minek ez a .clone() ide, lekapom, jo lesz", aztan ahogy probalja az ember vegigvinni az egesz kodon, derul ki, hogy azert kellett a clone(), mert minden thread-nek kell egy peldany. Es hasonlok. Ha nincs borrow checker, maris olyan hibat vetek, amit nem lett volna konnyu levadaszni.

Meg egy hatranya van a rust-nak: iszonyu gyorsan fejlodik, valtozik. Ami egy eve meg best practice volt, mara mar elavult kod. OK, pont az utobbi evben jott be az async/await, meg lett okosabb a borrow checker meg az implicit tipus-eldontes.

Nekem egyebkent az a benyomasom, hogy sok a hype korulotte, es sokan nem probaltak meg ki elesben. Szerintem a hype-olok fele feladna egy het szenvedes utan. :) Azert sokmindent lehetett volna benne egyszerubben, es talan C-szerubben csinalni. A legnagyobb fajdalmam az exception teljes hianya, ami miatt mindent egy Result<> -ba kell gyurni es mappelgetni a hibakat mindenhol. Iszonyu macera, teljesen feleslegesen. De ezen kivul sok feature, amit megszokott az ember egy modern nyelvtol, hianyzik.

Viszont, nemi tokolodessel lehet egy olyan statikus binarist forditani, amit a docker egy scratch containerben el tud futtatni.

 

(NB, mi a cegnel az idonk 20%-aban egy modern FTP serveren dolgozunk, GCS backenddel)

Köszi, hogy összeszedted, jó olvasni egy olyan véleményét, aki nap mint nap használja!

Rust hatalmas hatulutoje a meredek learning curve.

Ez lehet, hogy így van a legtöbb embernél, de az is sokat számít, hogy milyen háttértudással állsz neki. A borrow checker az vélhetően mindenkinek új, azt megtanulni a legnehezebb, de az egyik legfontosabb a biztonsághoz. Az összes többi tudását már más nyelvből ismertem, így nem volt gond azokkal, csak meg kellett ismerni, hogy mi mire való.

Hasonlo gyilkos az implicit conversion.

Ezt lehetőleg el kell felejteni, nem kell használni! Scalaban is van, de nem ajánlott a használata, illetve az új Scalaban már lesz helyette más, ami kiváltja azt a tudást, ami miatt leginkább kellett.

Szinten gond, hogy nincs normalis fejlesztoi kornyezet.

Ezt is aláírom, de ez se olyan fontos, ha már régóta olyan módon és szemlélettel programozol, ahol ennek nincs nagy szerepe.

Meg egy hatranya van a rust-nak: iszonyu gyorsan fejlodik, valtozik.

Ez valóban nagy hátrány, de gondolom most már ez egyre inkább le fog lassulni és kezelhető méretű lesz. Eddig ez nem volt nagy gond, mert kevesen használták éles rendszereken. Mivel egyre többen használják éles rendszereken, így egyre nagyobb lesz a nyomás is, hogy ne változzon olyan gyorsan.

A legnagyobb fajdalmam az exception teljes hianya

Pedig a borrow checker után ez a másik nagyon fontos feature, ami miatt biztonságosabb és érthetőbb programok készülhetnek.

ami miatt mindent egy Result<> -ba kell gyurni es mappelgetni a hibakat mindenhol. Iszonyu macera, teljesen feleslegesen.

Amikor mappelgetni kell mindenhol a hibákat, akkor az a legtöbb esetben egy figyelmeztetés is, hogy nem valami jól van szervezve a kód, pl. azt a dolgot, ami ott lent a hibát adja, azt kicsit feljebb kellene meghívni.

De ezen kivul sok feature, amit megszokott az ember egy modern nyelvtol, hianyzik.

Scala után se mondanám, hogy sok feature hiányozna a nyelvből, pedig Scalaban van minden is. Ami hiányzik nekem nagyon az az, hogy a rekurzív függvényhívás ne szálljon el stack overflow-val, legalább tail call hívás esetben. Ezt szeretnék is megoldani, de nem igazán tudják.

Egyelőre nincs. Pedig pár helyen szerettük a goto-t:
  - computed goto ... például gyors token interpretereknél
  - hibaágra való kiugrás

Rust esetén:
  - computed goto nincs, loop-ból break ÉRTÉK; van, bár ez az egyébként frankó megoldás a computed goto-t nem helyettesíti
  - hibaágra ugrás nincs, ? operátor viszont van, ami szintén frankón használható

Lehet értelmesen használni a GOTO-t. Van olyan programnyelv ahol nem lehet megkerülni a használatát.

A probléma igazából mindig abból akadt, amikor tömegesen van használva és olvashatóság szempontjából nagyon kibogozhatatlan kódot eredményez.

"Errors are red
My screen in blue
Someone help me
I've deleted Sys32"

>> Hasonlo gyilkos az implicit conversion.

> Ezt lehetőleg el kell felejteni, nem kell használni!

Nem a típusmegállapításra gondoltok?  Implicit konverzió - amennyire eddig tudom - egyáltalán nincs Rustban.  Az „explicit jobb, mint az implicit” elv alapján fejlesztik a nyelvet.  Egyszer Stroustrup Proftól megkérdezték, hogy mit változtatna az eredeti C++-on, ha visszamehetne az időben, és hát ezt.

A típusmegállapítás úgy tűnik, kivétel.  Generikus programozásnál itt-ott jól jöhet, de én is óvatos vagyok vele, szerencsére oda is lehet írni azt a típust.

> Amikor mappelgetni kell mindenhol a hibákat, akkor az a legtöbb esetben egy figyelmeztetés is, hogy nem valami jól van szervezve a kód, pl. azt a dolgot, ami ott lent a hibát adja, azt kicsit feljebb kellene meghívni.

Talán ezzel az egyel nem értek egyet;  a „mit honnan hívjunk”, az nekem ennél fontosabb szempontok alapján dől el.  Ettől függetlenül én is a Result<>-ot támogatom a kivétellel szemben, és amikor nagyon kell, akkor map-elgetek, de ritkán kell.  Olyan hibákra, amik biztos, hogy a fejlesztőnek szólnak, szívfájdalom nélkül pánikolok, a pánik meg tud mutatni stack trace-t.

Talán ezzel az egyel nem értek egyet;  a „mit honnan hívjunk”, az nekem ennél fontosabb szempontok alapján dől el.

Nem írtam semmilyen szempontot. Annyit írtam, hogy ez egy jelzés, hogy talán nem jól van szervezve a kód. Itt jön képbe az a fontos szempont, ami esetleg nem volt figyelembe véve és aszerint kell átalakítani a kódot, ahol már feltehetően nem kell 8 mélységben felfelé mappelgetni a hibát.

és amikor nagyon kell, akkor map-elgetek, de ritkán kell. 

Ezek szerint nálad nem igazán jelent ez problémát, nem jelez, hogy rosszul van szervezve a kód, mivel nem igen kell mappelgetned.

Ok, ha 8 mélységet keresztül kell map-elgetni, az tényleg jelezhet valamit. :)

Én nem gondolnám, hogy rosszul szervezem a kódot, még akkor sem, ha bevallottan szeretek absztrahálni, és gyakrabban (de indokkal) írok le .unwrap()-et.  Ahogy nő a bonyolultság, valamerre ugye terjeszkedni kell.  Ha nincs absztrakció, azt szokták spagetti-kódnak hívni.  Az, hogy hány rétegem van, az a bonyolultságtól függ.

Persze abban egyetértünk, hogy az átgondolatlan absztrakció legalább olyan rossz, mint a nem létező.

Régen volt olyan mániám - annó C-re csináltam libet makrókkal, aztán C++-ra exception-nel, aztán inkább a boost exception-t használva, - hogy ha hiba történt, minden szint szóljon valamit hozzá.  Mert az tényleg zavaró, hogy ha túl alacsony szinten szálltam ki, akkor fogalmam sem volt, hogy melyik lépés hívta.  Ha visszadobálás után magas szinten szálltam ki, akkor meg nem látszott, hogy pontosan mi miatt.  Végül a boost::exception a maga << operátorával egészen megtetszett, pedig amúgy nem kedvelem a boost-tal járó terhelést.  Aztán rájöttem, hogy legkevésbé se kell mindenkinek hozzászólnia, főleg, ha van stack trace.  Amikor néha kell, akkor map-pelgetek. :)  Ha mondjuk egy lib olyan esettel találkozik, amire van esély, hogy valaki futásidőben kezelni akarja, akkor pl. nem pánikolhatunk.

Rust esetén implicit konverzió nincs, olyannyira hogy az f32 (float) és az f64 (double) között sem tudsz közvetlenül műveletet végezni. Előbb mondd meg, hogy melyiket konvertálja melyikké. Tehát például az alábbi hiba nem marad rejtve Rust-ban:

#include <stdio.h>

int main() {
    float oszto = 1./3;

    int eredmeny = 4. / oszto;
    printf("4 / (1/3): %d\n", eredmeny);
}

Ugyanez a példa Rust-ban: https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gi…

A függvények fejlécében kötelező megadni a típust, a visszatérő típust szintén. Az automatikus típusmegállapítás csak függvényen belül játszik, de a fenti példában látjátok, hogy explicit módon bárhol megadható a típus, ahol picit is szükségét érzed (let oszto: f32 = ...).

Igen, a libet írtam a következő hozzászólásban.

Többszálú programnál nagyon meg kell gondolni, mi legyen.  Van egy jó hírem egyébként, a panic!() csak az aktuális szálat dobja ki.

Van olyan helyzet, pl. worker thread-eknél, ahol egy szál kieshet, tehát erre jó.

Van, ahol elromlik az egész folyamt, ha egy szál kiesik.  Sok esetben segíthet az std::sync::PoisonError. Ha egy Mutex vagy RwLock le volt foglalva, és úgy szállt el egy szál, akkor a többi szálban a zárolási kísérletek PoisonError-t adnak vissza.  Ez a hiba pedig tartalmazza az elhalt szál guard-ját, amit át lehet venni, és tovább működni vele(!).

> Ugye 2 hetnyi C tanulas utan mar akar a kernel kodot is olvashatja az ember.

Felőlem nyugodtan olvashatja, csak ne írja. :)  Illetve írhatja is, ha meggyőződött róla, hogy más nem olvassa, haha. :)  Bocs. :)

Komolyságot félretéve.

A libek minőségéről magára a nyelvre nem mondanék ítéletet, noha a gyakorlati használatra hatással vannak, de nem látom rossznak a trendet.

Egyébként ha Te magad explicite megadod a saját típusaidat, az sokat segít, mondjuk a hypert még nem használtam, nem tudom, mi mindent rejt.

A fordító hibaüzenetei amúgy általában elsőrangúak.  Gyakran odaírja azt is, hogy melyik modult kellene használni.  Ha generikusan is programozol, az persze rátesz a nyelv nehézségére még egy lapáttal, de a fél képernyős hibaüzenet (ami szellős, és forrássorokat idéz) nekem barátságosabb, mint a C++ esetenként 3 oldalas és tömör hibaüzenetei.  Oké, van olyan is, amikor nem egyszerű rájönni, hogy mit mond.

Azert abba kemeny belegondolni, hogy ahogy Steve Jobs kinyirta a Flash-t, ugy nyirta ki majdnem Linus Torvalds a C++-t. Annyi, hogy a C++ azota is optimalis valasztas nehany helyre, de sokkal altalanosabban hasznalt valami lehetne mostanra (is).

Ha a "biztonsagos" alatt a managedet erted, hogy nehez rosszul cimezni egy pointert, akkor kb annyira nem az, mint a C, foleg ha ugy hasznalod es C libeket hasznalsz benne. Olyat is lattam, aki include cstdlib es malloc-olt es free-zett C++-ban new es delete helyett. Olyat is lattam, aki azert csinalta, mert fogalma sem volt, de olyat is, akinek magyarazata is volt ra, nem volt neki a new meg delete elegge zero overhead (nem tudom, hogy a magyarazat megallta-e a helyet).

Viszont egyvalami biztosan elmondhato a C++-rol: a legfejlettebb szignifikans platformfuggetlen konyvtarhatterrel rendelkezo zero-overhead policy-s nyelv. Change my mind.

Mielott valaki azzal jonne, hogy "mar nem fontos a zero overhead policy", azokrol azok a devek jutnak eszembe, akik nem ertik, mi a jo a C++-ban, es azt sem ertik, hogy miert baj, hogy egy electronos app 10 sec-ig tolt be, aztan megeszik 1.5GB RAM-ot, hogy megjelenitsen egy haromoszlopos tablazatot.

>Mielott valaki azzal jonne, hogy "mar nem fontos a zero overhead policy", azokrol azok a devek jutnak eszembe, akik nem ertik, mi a jo a C++-ban, es azt sem ertik, hogy miert baj, hogy egy electronos app 10 sec-ig tolt be, aztan megeszik 1.5GB RAM-ot, hogy megjelenitsen egy haromoszlopos tablazatot.

Hát, pedig ha szigorúan nézzük, akkor az electronos appok 99,999%-a C++ban van írva (a Chromium motor ami csomagolva van beléjük), a JS rész hozzájuk inkább egy kitekert konfigfájl csak. :^)

Biztonság terén a malloc és a new között kevés különbség van (oké, a new legalább típusbiztos).  Inkább a shared_ptr-t hoznám, mint előnyt.

... bár arra sokszor nincs szükség, elég lenne unique_ptr, az meg nem másolható, ez néha korlátozó tényező, a move meg C++-ban kicsit nehéz, és nagyon nem biztonságos...  és megérkeztünk a Rusthoz. :)  Mikor használnál dinamikus memóriát?

  • Ha futáskor dől el valaminek a mérete vagy elemszáma: vannak konténerek, az alkalmazásnak nem kell dinamikus memóriát kezelnie.
  • Ha az A modul inicializál valamit, de B modul fogja tartalmazni: szintén nem kell, move szemantikás a nyelv.

> nem volt neki a new meg delete elegge zero overhead

Amúgy ja, én azzal szoktam találkozni, hogy "a C++ azért lassú, mert mindenféle függvénypointereken keresztül mennek a hívások";

de ugye a) az esetek túlnyomó részében ez mérési hiba alatt van;  b) gondoljunk bele, mikor kell virtulális metódus;  leginkább olyankor, amikor C-ben vagy switch-case-zel válogatnék közöttük, vagy callback-táblázattal, tehát ugyanott vagyunk.

Mondjuk azt sajnálom, hogy C++-ban (még) nincs rendes fordításidejű polimorfizmus, olyankor RTTI-s objektumokat kell csinálni, ha szeretnék közös őst.  C++20-astól jön a concept C++-ba is.

Szerintem biztonsagosabb lett, de ugyanazokat a hibakat el lehet benne kovetni, mint korabban. Viszont megjelentek olyan elemek a nyelvben (es az STL-ben), amiket jol hasznalva a problemas esetek szama es a fejben tartando "implicit" konvenciok szama csokkentheto. Pont ez a Rust elonye az en szememben: probaljak teljesen (ertsd logikailag igazolhatoan) eliminalni a memoriahibakat. Ertsd: ha fordul a rust program, akkor nincs benne sem memleak, sem memoria korrupcio, vagy barmi egyeb "undefined behaviour", ilyen garanciakat a c++ fordito nem ad, valoszinuleg soha nem is lesz erre kepes.