Cookies op Tweakers

Tweakers maakt gebruik van cookies, onder andere om de website te analyseren, het gebruiksgemak te vergroten en advertenties te tonen. Door gebruik te maken van deze website, of door op 'Ga verder' te klikken, geef je toestemming voor het gebruik van cookies. Wil je meer informatie over cookies en hoe ze worden gebruikt, bekijk dan ons cookiebeleid.

Meer informatie

Rust 1.49.0 met Tier 1-ondersteuning voor 64-bit-Arm-Linux-systemen is uit

De ontwikkelaars achter Rust hebben Rust 1.49.0 uitgebracht. In de nieuwe stable release zit onder andere betere ondersteuning voor 64-bit-Arm-infrastructuren voor Linux.

Rust 1.49.0 is net voor het nieuwe jaar uitgekomen. De belangrijkste wijziging erin is dat ondersteuning voor 64-bit-Arm-Linux-systemen een 'Tier 1'-status heeft gekregen. Dat betekent dat de programmeertaal de hoogst mogelijke ondersteuning van de ontwikkelaars krijgt. Onder een Tier 1-status worden nieuwe versies na iedere verandering in de compiler op alle ondersteunde systemen gedraaid om bugs te vinden. Rust was al langer wel beschikbaar op 64-bit-Arm-Linux-systemen, maar alleen met een Tier 2-status waarbij de ontwikkelaars alleen garanderen dat de build gecompileerd wordt, maar waarbij mogelijk nog bugs in de code zitten. Het is de eerste keer dat een niet-x86-target die Tier 1-status haalt.

Met de nieuwe versie van de programmeertaal worden ook 64-bit-systemen Arm-systemen op macOS en Windows ondersteund; die gaan van een Tier 3- naar Tier 2-status. Dat betekent dus een garantie dat builds uitgevoerd worden, maar ook dat prebuilt-binaries beschikbaar worden gesteld. De ontwikkelaars zeggen daarnaast dat Rust 1.49.0 drie nieuwe stable functies heeft: slice::select_nth_unstable, slice::select_nth_unstable_by en slice::select_nth_unstable_by_key. Volgens de changelog zijn er ook nog andere kleine wijzigingen.

Wat vind je van dit artikel?

Geef je mening in het Geachte Redactie-forum.

Door Tijs Hofmans

Redacteur privacy & security

01-01-2021 • 11:05

104 Linkedin

Reacties (104)

Wijzig sortering
Het is mooi dat Rust echt flink aan het groeien is en ARM als Tier 1 neerzet. Ik hoop in de nabije toekomst dat ook RISC-V een belangrijke rol gaat spelen, en natuurlijk WASM als target een zeer belangrijke rol gaat spelen.

Wat kan je allemaal met Rust programmeren?
- ARM Microcontrollers
- ARM SoC's.
- RISC-V Microcontrollers
- RISC-V SoC's
- X86 natuurlijk.
- WASM

Ik kan wel stellen dat Rust na C, de meeste platformen ondersteund. (Vooral moderne nieuwe platformen) wil je oudere en wat meer "unieke" platformen ondersteunen blijft C natuurlijk heer en meester. Maar je kan van Microcontroller, naar multi-core supercomputers tot aan web-servers, Kernels, en zelfs Front-End websites / apps voor je browsers programmeren. En dat allemaal met performance dat dicht bij C ligt maar dan in een moderne taal met de nieuwste technieken.

En er wordt wel eens vaak beweerd dat de Total Cost of Ownership met software geschreven lager zal liggen dan in een andere taal. Puur vanwege dat je minder onderhoud nodig hebt. (Net als Elektrische auto's minder onderhoud nodig hebben, maar wel duurder zijn.)

Rust is voor mij persoonlijk de meest veelbelovende taal van de komende 30 jaar.

[Reactie gewijzigd door Immutable op 1 januari 2021 13:52]

Rust is voor mij persoonlijk de meest veelbelovende taal van de komende 30 jaar.
Ja, maar toch ook nee. :)

Ik heb wel eens gelezen van kleinschalig onderzoek waaruit bleek dat, op assembly na, ervaren softwareontwikkelaars met elke gekozen taal net zoveel tijd nodig hadden om het probleem op te lossen. Rust, Swift, Go, Kotlin, Elm, proberen allemaal een ander probleem op te lossen met een nieuwe taal. Ondertussen groeit het aantal talen, blijft ondersteuning voor tools achter en moeten ontwikkelaars steeds iets nieuws leren. Je kunt je afvragen of die energie niet beter op bestaande talen gericht kan worden. Ik vind Rust cool en veelbelovend, maar als ik anderen enthousiast hoor over een andere nieuwe taal dan bekruipt mij het idee dat iedereen een beetje gelijk heeft; en daarmee niemand.
Moet je maar eens aankomen bij C++ of ze niet even bepaalde "defaults" omdraaien zoals dat standaard een variabele mutable is. Het kan wel, maar zal never nooit gebeuren.
Er zijn bepaalde zaken binnen alle talen die ze nooit zullen veranderen, ook al zijn ze er van bewust dat het gewoon een fout is. Daarom moet er of een afsplitsing komen of een nieuwe taal.

Ben het trouwens volkomen eens met je laatste zin. Voor mij blijft alles gewoon een evolutie. Binnen de talen, als in nieuwe talen. Er is ook een toekomst na Rust, want in Rust zijn er ook problemen. En als de ontwikkeling op talen parabolisch gaat... kan die 30 jaar ook wel 10 jaar worden. ;)

[Reactie gewijzigd door Immutable op 1 januari 2021 14:18]

Moet je maar eens aankomen bij C++ of ze niet even bepaalde "defaults" omdraaien zoals dat standaard een variabele mutable is.
Klopt; maar een goede IDE (not talking to you, Visual Studio!) geeft aan dat je een variabele (of parameter, method) const kan, en zou moeten, maken en biedt aan dit voor je te doen.
Een goede IDE kan dat misschien voor je doen. Maar een goede engineer laat zich nou niet bepaald leiden of beperken door zijn IDE. De praktijk is eerder dat de engineer functions te vaak const maakt, en uit noodzaak overloads zonder constness erbij moet zetten (een compromis om niet aan redesign/refactoring te hoeven beginnen).
Maar een goede engineer laat zich nou niet bepaald leiden of beperken door zijn IDE.
Dat klinkt bijna als
Een goede engineer negeert compiler warnings, leest ze niet eens, want hij weet echt wel waar hij mee bezig is.

[Reactie gewijzigd door 84hannes op 1 januari 2021 21:02]

Misschien bijna, maar toch niet helemaal. Je compiler staat los van je IDE. Ook bij MVS. Je IDE laten bepalen wat const is of niet klinkt alsof je bakstenen voor je nieuwbouw huis aan het leggen bent zonder dat je weet of je met de zolder of de kelder bezig bent.

[Reactie gewijzigd door Epsix op 2 januari 2021 05:22]

Misschien bijna, maar toch niet helemaal. Je compiler staat los van je IDE.
In Rust werkt men sinds Rust Analyzer eraan om de linter (in Rust's geval, Clippy) als backend te gebruiken voor de IDE; met andere woorden, de fouten en waarschuwingen die je in de IDE krijgt, komen rechtsstreeks van Clippy, en dus de compiler (want Clippy gebruikt de compiler op de achtergrond om zijn waarschuwingen en suggesties te construeren).

Als je de waarschuwingen en suggesties in je IDE negeert, dan krijg je die gewoon (weer) als je compileert, en je kunt ervan uitgaan dat je programma dan sub-optimaal is. Clippy is, in tegenstelling tot zijn jaren-90 voorganger in Office, heel goed in wat hij doet.
Krijgen we dan niet van die Java praktijken waar 1 bedrijf achter de richting en tooling van Rust zit? Ik heb redelijk veel vertrouwen in de consensus van het C++ consortium wat dat betreft. Ik vind de ontwikkeling van gnu, mingw, nmake, clang, met daarboven op de build systems, en daarboven op de tooling interessant om te volgen. Het spanningsveld en de samenwerking tussen alle partijen maakt vooruitgang langzaam, maar elke stap is een significante en juiste.

Maar we zullen zien met Rust. Ik heb er veel goeds over gelezen. Het lost problemen op waarvan ik niet echt vond dat het problemen waren. Maar misschien gaan we nu zien dat software ontwikkeling een enorme boost van kwaliteit gaat krijgen.
Krijgen we dan niet van die Java praktijken waar 1 bedrijf achter de richting en tooling van Rust zit? Ik heb redelijk veel vertrouwen in de consensus van het C++ consortium wat dat betreft. Ik vind de ontwikkeling van gnu, mingw, nmake, clang, met daarboven op de build systems, en daarboven op de tooling interessant om te volgen. Het spanningsveld en de samenwerking tussen alle partijen maakt vooruitgang langzaam, maar elke stap is een significante en juiste.
Nee. Er komt een Rust Foundation. Iedereen kan bijdragen aan de taal en/of in die Foundation zitten.

"Vroeger" was RLS (Rust Language Server) de default backend voor de meeste IDE's, maar nadat Rust Analyzer van Ferrous Systems sneller en krachtiger bleek te zijn én beter te onderhouden, heeft het Rust Core Team op een gegeven moment besloten om Rust Analyzer als default te verklaren.
Maar we zullen zien met Rust. Ik heb er veel goeds over gelezen. Het lost problemen op waarvan ik niet echt vond dat het problemen waren. Maar misschien gaan we nu zien dat software ontwikkeling een enorme boost van kwaliteit gaat krijgen.
Rust zorgt ervoor dat de meest voorkomende problemen in C/C++ niet meer voor -kunnen- komen:
- unsafe geheugengebruik is niet mogelijk (borrow checker)
- unsafe delen van objecten/structs/geheugen tussen threads is niet mogelijk
- variabelen al gebruiken voor je ze initialiseert kan niet (compileert niet)
- globale variabelen zijn niet eens mogelijk

Als je programma goed in elkaar zit, kun je ervan uit gaan dat indien het compileert, het ook werkt. (Het betekent niet dat het nooit kan crashen; als er uit een berekening "50" komt en je gebruikt dat als index voor een array met maar 30 elementen, dan krijg je een panic voor je kiezen. In C zou je echter gewoon buiten de array schrijven en blijft het programma doordraaien, met alle gevolgen van dien.)
globale variabelen zijn niet eens mogelijk
Volgens mij zijn er mogelijkheden met een shared reference.
Heel eerlijk gezegd heb ik 4 jaar geleden ook al een "ik ben benieuwd/we zullen zien" comment over Rust binnen wat discussies achtergelaten. Ik kan nou niet zeggen dat mijn ogen sindsdien geopend zijn naar de revolutie die het teweeg heeft gebracht.

Ik snap de mission van rust wel hoor. En er is vast wel plek voor programmeer taal #83 in onze alsmaar groeiende industrie. Maar als ik eerlijk ben denk ik dat het voornamelijk grond van Java, en Haskell gaat snoepen, en maar minimaal van C++.

Rust voelt aan als een "best practice" versie voor C++. Een redelijk specifieke manier van denken hoe software design zou moeten zijn. Daarmee spreek je per definitie al een minderheid aan binnen C++ gebruikers. Maar ik ben benieuwd. Misschien is GTA VI laat omdat het met Rust geschreven wordt? We zullen zien.
Het "een echte developer" cliché is nog een symptoom binnen het gilde, van het onderliggende probleem van ego'tjes onder developers.
Het steeds nieuwe talen en frameworks willen ken ook. Wijs mij een dev aan die niet opschept over die nieuwe taal of framework dat hij/zij geleerd heeft, en ik eet mn spreekwoordelijke schoen op.
Wijs mij een dev aan die niet opschept over die nieuwe taal of framework dat hij/zij geleerd heeft
Iedereen boven de dertig :)

Als je onder de 15 bent vindt je nieuwe dingen normaal. Tussen 15 en 30 zijn nieuwe dingen cool; na je dertigste levensjaar zijn nieuwe dingen overbodig.
Overbodig niet. Maar een hassle zeer zeker ;-D

*Weer* wat nieuws om te leren en bij te houden...

Ook leuk natuurlijk, maar ik word er ook wel eens moe van.

40+er speaking...
Klopt tooling kan een hele hoop fixen, buitenom de taal. Daar heb je helemaal gelijk in! Daar kan dus nog veel uitgeperst worden.
Moet je maar eens aankomen bij C++ of ze niet even bepaalde "defaults" omdraaien zoals dat standaard een variabele mutable is. Het kan wel, maar zal never nooit gebeuren.
Omdat je niet even decenia en miljarden regels code kan breken. Ala "We do not break userland, period." ;) Dat is ook waarom nieuwe talen soms naief makkelijk denken over dat soort dingen en een handje hebben van breaking changes omdat het nog kan. Stel nu dat je 30 jaar verder bent en Rust is heel groot, dan zullen er ook "fouten" ontdekt worden die niet meer aan te passen zijn -- of wel maar daar ga je jezelf geen populaire taal mee maken voor de komende 30 jaar...
Je zou natuurlijk wel voor kunnen kiezen om bij het uitbrengen van een nieuwe C++ standaard los te laten van backward compatibility dat zou in principe geen grote problemen moeten opleveren. Oude code is nog steeds te compileren met een oudere standaard.

Het enige probleem dat ik kan bedenken is dat je oudere versies van standaarden moet gaan blijven onderhouden.
Ja incompatibilities introduceren is ook bij python3 gebeurd. Heeft behoorllijk wat ellende opgeleverd
Python is niet gecompileerd dus dat is een ander verhaal. Dan moet je naast de standaard ook een interpreter onderhouden wat meer tijd/aandacht vergt dan een compiler onderhouden. Plus python is een grote teringzooi aan libraries waar je bij C/C++ met de std library vrij ver komt.
Dan moet je naast de standaard ook een interpreter onderhouden wat meer tijd/aandacht vergt dan een compiler onderhouden.
Is dat zo?
Rust heeft zogenaamde Editions.

De eerste edition is 2015: Rust 1.0 t/m 1.30
De huidige edition is 2018: sinds Rust 1.31

Het is de bedoeling dat de compiler alle voorgaande edities modulair blijft ondersteunen: als je een programma dat is geschreven in Rust Edition 2015 (dus vanaf 1.0 t/m 1.30) compileert met een Edition 2018, 2021, of 2030 compiler, dan zou dat programma gebuild moeten worden alsof je het aan het bouwen bent met Rust 1.30.

Op deze manier kun je een programma dat geschreven is in Rust 1.21 (onderdeel van Edition 2015 dus) gewoon compileren met Rust 3.27 (Edition 2030 ofzo). Je kunt dan in 2 stappen migreren:

- Wijzig "edition 2015" in "edition 2018"
- Los alle (syntactische) fouten die de compiler aangeeft op

En dan ben je dus gemigreerd naar Edition 2018, en dan wordt het programma gecompileerd met Rust 1.49 (op dit moment; of later, de laatste versie die nog onder 2018 valt). Zo kun je stap voor stap relatief gemakkelijk van de ene naar de andere edition migreren totdat je bij de laatste aankomt. Dit zorgt er dus voor dat je bij een overstap naar een nieuwere compiler niet opeens met 3200 foutmeldingen komt te zitten omdat je van Rust 1.0 naar Rust 3.27 gaat.
Rust heeft - anders dan bijvoorbeeld de Linux kernel of C++ - wel een redelijk verhaal rond het maken van breaking changes, deprecation en uberhaupt het evolueren van de taal zelf. Zie bijvoorbeeld de RFC over semantic versioning van de taal (https://github.com/rust-l...t/1122-language-semver.md) en de documentatie omtrent het fixen van (potentially breaking) bugs https://rustc-dev-guide.rust-lang.org/bug-fix-procedure.html
Als het goed is, hoef je als ontwikkelaar niet zo heel veel nieuws te leren. Als je C++ kan, kun je in mum van tijd ook C#, Java, Kotlin, Go en Swift. De onderliggende concepten zijn niet heel anders, er zijn alleen bepaalde regels en naampjes die je even moet leren kennen.

Elm is dan weer net wat anders omdat het een functionele taal is. Ken je al een functionele taal zoals Haskell of F#, dan is het ook weer niet echt een grote stap om Elm te leren.

Het verschil is hier dat Rust niet echt veel professionele competitie biedt voor de andere talen die je noemt. Ja, er worden best wel coole projecten gemaakt met Rust, maar de echte concurrent die Rust probeert te vervangen is C++ en tot zekere hoogte C.

Een browser-rendering-engine schrijf je niet in Elm of Kotlin, omdat je te maken hebt met een soort applicatie waar iedere instructie telt, waar alles altijd snel moet. Hetzelfde geldt voor een systeemlibrary als OpenSSL of libxml2, die code moet gewoon native. De kracht van Rust is dat het een programmeertaal is die met moderne abstracties uit talen als Kotlin en Swift toch nog low-levelcode kan worden geschreven die qua snelheid in de buurt van geoptimaliseerde/complexe C en C++ zit.

Ook voegt Rust een hele hoop veiligheid toe aan low-level code die je normaal niet zomaar kunt afdwingen. Ja, met de juiste code standards, een hele hoop code review en competente programmeurs kun je prima de veiligheid van Rust evenaren, maar die extra moeite hoef je niet te doen als je dat vervelende werk gewoon uitbesteedt aan de compiler. De taalstandaard kan niet ineens verplichten dat pointers alleen met een bepaald keyword kunnen worden overschreven, alleen dat je kunt aangeven met een nieuw keyword dat je dat niet wil hebben; als je extra restricties oplegt, doet ineens oude code het niet meer en dat kun je niet maken met een uitbreiding van de standaard.

Er zijn zat problemen met Rust momenteel, en de taal is nog lang niet klaar om je hele systeem in om te schrijven. Ik denk ook niet dat het ooit Java of C# gaat vervangen zoals Kotlin dat op Android heeft gedaan. Ook denk ik niet dat we snel de Linux-kernel zullen zien worden omgeschreven naar Rust.

Ik denk wel dat een hele hoop utilities die nu puur uit snelheidsoverwegingen in C(++) worden geschreven, uiteindelijk naar Rust zullen kunnen komen. Hierbij denk ik aan package managers, programma's als curl en wget, tools als find en fzf, services als DNS-servers of webservers (en dan nginx-achtig, niet Spring Boot/Node-achtig) en misschien zelfs bepaalde belangrijke delen van dingen als systemd.
What about Go vs Rust? Is de community daarvan niet een stuk groter? En Correct me if i’m wrong, maar Go is ook vrij snel en scheelt niet veel met C.
Rust heeft een heleboel sterke punten, maar het onderscheidende voordeel is de manier waarop geheugen wordt beheerd. Iedere andere taal die ik ken heeft ofwel een garbage collector, ofwel manueel beheer. Go heeft dat eerste; dit kan negatieve gevolgen hebben voor de performance (onvoorspelbaarheid). Het is daardoor minder geschikt om bijvoorbeeld een browser of besturingssysteem in te programmeren.
Thanx! Voor toekomstige lezers, hier een link met beter/dieper uitleg met betrekking tot Garbage Collection in Rust;

https://stackoverflow.com/a/32678736
"Unfortunately, after 30 years professional in software, I find the main problem is that "a bad programmer can write bad code in any language", to paraphrase the famous saying. And most programmers are pretty bad.

Good programmers avoid unsafe practices anyway, so new and better languages don't provide the advantage that is hoped."


(Ik had het kunnen vertalen maar ik denk dat het wel duidelijk is voor de meesten hier.)
Oneens. Naast dat programmeurs niet enkel in een "good" en "bad" categorie te plaatsen zijn, verlicht het de mental burden tijdens het ontwikkelen enorm wanneer de compiler de afwezigheid van bepaalde fouten garandeert. Alleen al het ontbreken van een null-pointer zou al verscheidene bugs die ik ben tegengekomen voorkomen hebben.
En inderdaad is het aantoonbaar afwezig, de checker controlleert dat deze fouten afwezig zijn. Dat is wat anders dan dat je zegt: ik denk dat het fout vrij is, maar ik kan het niet aantonen. Iets bewijzen is veel sterker dan iets vermoeden.
Ja, dat is wat ik bedoelde met dat de compiler de afwezigheid garandeert. Dat is op zich al een audit. Maar voor mij is misschien wel de grootste plus iets wat ik ook met Haskell ervaren heb: door de confidence die je in de output kan hebben ben ik meer bezig met structuur en algoritmes dan met het correct gebruiken van geheugen. Dat scheelt gewoon werkplezier en productiviteit.
Ja, ik snap wat je bedoelt. Nou kun je met c++ ook wel sanitizers gebruiken en daar kom je ook een heel eind mee. En als je voldoende ervaring hebt in c++ worden die geheugen fouten eigenlijk ook een stuk minder. Nadeel van rust vind ik dat het heel restrictief is. Zoiets als een linked list is ondoenlijk. Het keurt ook heel veel dingen af die in principe wel correct zouden kunnen zijn. Waar je dan omheen moet werken.
Nadeel van rust vind ik dat het heel restrictief is. Zoiets als een linked list is ondoenlijk. Het keurt ook heel veel dingen af die in principe wel correct zouden kunnen zijn. Waar je dan omheen moet werken.
Dat is inderdaad de concessie. Een doubly linked list or enige vorm van graph wordt inderdaad onmogelijk gemaakt omdat de compiler de correctheid daarvan niet kan garanderen. Maar nou is specifiek het voorbeeld van een linked list met een zeer eenvoudig stukje unsafe code wel omheen te werken.
Maar juist omdat je de "unsafe" code in een super klein hoekje drukt. Kun je dus heel goed op dit stukjes extra controle op doen. Zonder dat je de gehele code door moet. Puur en alleen waar staat unsafe {} moet je niet zien als evil.... ( Sommige mensen binnen de Rust community werden helemaal afgezeken, omdat ze unsafe gebruikten in hun code wat echt belachelijk is maar goed. Zie Actix-web drama)
Je moet unsafe niet als "evil" zien, maar een optie wanneer je goede redenen hebt om die te gebruiken, dus gebruiken kan. Denk aan: Hier ga ik safety even ruilen voor performance. (klein stukje code) wat erg goed te reviewen is door verschillende mensen, en makkelijk op te zoeken is als er eventueel wel een bug is die daarmee te maken kan hebben. Unsafe moet je dus eigenlijk kiezen, wanneer het niet anders kan... of wanneer je bewust een keuze maakt voor iets anders. Sleutel hierbij is: Je bent bewust van waarom je unsafe gebruikt. Soms is er geen fundamentele zilveren kogel, en moet je een keuze maken. Zie ook https://nl.wikipedia.org/wiki/CAP_theorema

[Reactie gewijzigd door Immutable op 1 januari 2021 13:35]

Maar door dat kleine stukje unsafe verlies je dus het bewijs van de formele checker. Ik kan wel begrijpen dat dat als evil wordt gezien. Er bestaat niet zoiets als grotendeels correct bewijs
En dat kleine stukje is nog wel door mensen te auditen, iets wat er met de software waar ik aan werk sowieso moet gebeuren vanwege de ISO-certificering. Daarbij maakt het in de praktijk zeker wel verschil: zelfs als de probabiliteit van incorrect geheugengebruik even hoog is in een unsafe block als in een "onveilige" taal, is de N waarop deze kan plaatsvinden alsnog een fractie. In de praktijk zul je dus veel minder veiligheidsproblemen zien, en dat is toch uiteindelijk waar het om draait.
Het is beetje de discussie praktisch vs theoretisch. Praktisch zal het wel goed werken, maar theoretisch gezien heb je geen bewijs dat het 100 procent correct is. Maar als je een bedrijfskritisch systeem hebt, in een auto, vliegtuig of een defensie systeem, kan ik mij voorstellen dat de eis wordt dat het formeel 100% kloppend moet zijn. En dat unsafe code dus niet een onderdeel mag zijn.
Lijkt me prima mogelijk dat je daar een uitzonering voor kunt maken voor gevallen waarin je theoretisch kunt bewijzen dat een oplossing zonder unsafe onmogelijk is.
moet je wel eerst even bewijzen dat het onmogelijk is zonder unsafe code. Dat is nog niet zo makkelijk denk ik. Het is waarschijnlijk makkelijker te bewijzen dat het wel kan met safe code.
En dat unsafe code dus niet een onderdeel mag zijn.
Uiteindelijk, op enig niveau, vallen abstracties weg en zul je fysiek geheugen moeten adresseren.
Met die redenatie kunnen we net zo goed in assembly gaan programmeren. Programmeertalen zijn enkel een schil daar omheen.

[Reactie gewijzigd door wkleunen op 1 januari 2021 17:11]

Je trekt het lekker door.

Een auto heeft bewegende onderdelen die afgeschermd worden voor de consument en de elementen. Het zou vervaarlijk zijn als je met je vingers tussen de cilinders kunt komen. Maakt dat een auto 100% veilig? Nee! De wielen draaien, de uitlaat wordt heet. Maar de auto is nog steeds veiliger door die afscherming omdat het aantal ‘unsafe’ elementen wordt geminimaliseerd.

Alle code schrijven zonder ‘unsafe’ is eenvoudigweg niet mogelijk, net zomin als je een auto kunt maken zonder bewegende onderdelen aan de buitenkant. Het idee van ‘unsafe’ is het lokaliseren en minimaliseren van onveilige acties.

[Reactie gewijzigd door 84hannes op 1 januari 2021 21:36]

Ja. En dat zijn toch wel de standaard.data structuren in de informatica. Dat is dan toch jammer. En andere jammere is dat er geen manier is om rust en c++ met elkaar te laten praten. Alleen via een c interface. C++ is toch wel een standaard, en het zou handig zijn kleine stukken in rust te schrijven om deze formeel correct te maken. En de rest in c++
Dat laatste inderdaad. Als die mogelijkheid er was zou ik binnen mijn huidige werkplaats pleiten om nieuwe modules voor de software in Rust te gaan schrijven. Maar dit was sowieso een groots gehoorde wens bij de laatste Rust survey.
En waar werk je dan, als ik vragen mag ?

Hou er wel rekening mee dat het regelmatig voor komt binnen software projecten, dat dan bepaalde stukken worden omgeschreven naar framework X or programmeertaal Y, omdat die bepaalde dingen beloven. Echter na aantal jaar, wordt het dan weer terug geschreven naar een gangbare programmeertaal, omdat er voor framework X of programmeertaal Y geen ontwikkelaars te vinden zijn. En de beloftes zijn eigenlijk ook nooit nagekomen.

[Reactie gewijzigd door wkleunen op 1 januari 2021 17:22]

Bij een softwareontwikkelaar voor de luchtvaartindustrie.

Het is dus inderdaad belangrijk dat een toolset voldoende tractie heeft. Nu Amazon, Microsoft en Facebook dedicated Rust teams hebben lijkt me dat wel van toepassing.
Maar ik denk dat het niet voldoende voordelen heeft. Met sanitizers en statische analyse kom je eigenlijk net zo ver met C++: Sanitizers. Bepaalde bugs zijn eigenlijk alleen dynamisch te detecteren (bijvoorbeeld index out of bound of integer overflow). Daar brengt Rust geen verandering in, dus dynamische analyse hou je toch. Dan heeft het geen zin om alle bestaande C++ code om te gaan schrijven naar Rust.
Is niet echt een linked list te noemen die implementatie, ondersteunt namelijk geen insertion in het midden. Wat juist de reden is om voor een linked list te kiezen:

https://rcoh.me/posts/rust-linked-list-basically-impossible/
Ah ok, niet bij stilgestaan, heb eigenlijk nog nooit nood gehad aan een linked list in mijn rust projecten.

Stel dat het wel zou kunnen in deze library welk voordeel heb je tov een Vec ?

In mijn C projecten gebruikte ik die wel geregeld.
Je kunt dan data inserten in het midden van de lijst met een tijdscomplexiteit van O(1). Bij een Vec moet je de elementen die na het punt komen dat je insert allemaal naar achter kopieeren, of soms zelf een nieuwe geheugen allocatie doen en de hele vector over kopieren. Dit heeft dan tijdscomplexiteit van O(N).

Voor sommige algoritmen of data structuren (bijvoorbeeld de trie), is dit van belang dat die operatie die tijdscomplexiteit heeft. Omdat dat bepaalt hoe snel het algoritme functioneert als de input groeit.

In de praktijk pak je inderdaad vaak gewoon een Vec.
In een LinkedList kun je ook niet in het midden inserten in O(1), want je moet eerst nog een reference hebben naar de nodes eromheen. Die kun je alleen krijgen door eerst over de LinkedList te iteraten, wat altijd in O(n) moet gebeuren.
Ook in een doubly linked list is de insertion time nog O(n), maar er komt een constante 1/2 voor, omdat je altijd van de kortste kant kunt iteraten.
Dat is de 'traversion' of 'search' van de list, wat jij bedoelt:
https://en.wikipedia.org/wiki/Doubly_linked_list

Voor de insertion wordt aangenomen, dat je al weet voor welke node je de nieuwe node moet inserten. De manier waarop jij rekent zou zeggen dat als je de data in een vector op slaat, je eerst moet zoeken O(n) en dan daarna inserten O(n), de complexiteit voor een vector insert dan O(n*n) is.

Zie ook:
https://www.bigocheatsheet.com/

Doubly en Singly linked list maakt trouwens niet uit voor insertion. Bij die X-Trie wordt het blijkbaar doubly omdat: To enable O(1) predecessor and successor searches once you have a leaf node, the values are stored in a doubly linked list.

[Reactie gewijzigd door wkleunen op 8 januari 2021 19:00]

Nu ik het lees herinner ik mij het weer. Het zit allemaal een beetje ver. Bedankt voor de opfrissing
Ik vind de restricties van Rust eigenlijk juist een voordeel. Ik heb zelf eigenlijk nooit echt een linked list nodig gehad waar ik geen iterator heb kunnen gebruiken, en het gebrek aan bomen is met wat simpele algoritmes vaak ook wel te omzeilen. Er zijn natuurlijk wel gevallen dat je tegen de beperkingen van Rust aanloopt, maar in de dagelijkse praktijk kom ik ze eigenlijk nooit tegen.

Het is wel lastig om dingen als binaire bomen te maken, specifiek als je de waardes binnen die bomen gaat aanpassen en/of omdraaien. Dat is dan wel weer te doen door de "boom" als algoritme op een lijst of array te implementeren, waardoor je dezelfde operaties kan uitvoeren op het object zonder de problemen die je met pointers kunt krijgen, maar dat is niet zo makkelijk als een simpele boom in C++ uitwerken.

Dat het dingen afkeurt die in principe goed kunnen zijn, vind ik nou de kracht van de taal. Als de compiler je een OK geeft (zonder unsafe te schrijven) weet je gewoon zeker dat je oplossing goed is, terwijl de assumptie "volgens mij is dit gewoon correct" in de praktijk vaak niet correct blijkt te zijn. Het kost meer werk, maar de nodige unit tests schrijven om te bewijzen dat je implementatie geen geheugen lekt en de bijbehorende code-analyse uitvoeren kost dat ook.
Bijzondere mening. Het een kracht van een taal vinden, als hij dingen afkeurt die in principe gewoon goed zijn. En zoals verderop ook al gezegd, de checker controleert dus niet op geheugen lekken. Ook in Rust moet je nogsteeds zelf aantonen dat er geen cyclische referenties zijn waardoor geheugen lekken onstaan.
Dus ook voor je Rust code moet je nogsteeds die unit tests schrijven, voor functionaliteit, en ook voor geheugen lekken.

http://huonw.github.io/bl...ry-leaks-are-memory-safe/

Maar een boom als een array gaan implementeren, als je dan toch geen zorgen maakt over performance, dan kun je beter in een managed taal gaan ontwikkelen zou ik dan zeggen. Gebruik dan Go ofzo, denk dat dit in de praktijk ook gebeurt, want Go is veel populairder dan Rust.

https://madnight.github.io/githut/#/pull_requests/2020/3
De makers van de taal bepalen wat in principe goed is. In correcte Rust zijn directe pointermanipulaties niet goed. In normale Java zijn ze dat ook niet (alhoewel je theoretisch met reflection nog wel kan klooien). Dat jij vindt dat het goed is, maakt het nog niet meteen goed in de context waarin je je momenteel bevindt.

Dat bij Rust unit tests nodig zijn is natuurlijk overduidelijk. Het verschil is dat je geheugenveiligheid niet meer hoeft te bewijzen met unit tests. Dat zijn toch een stel hele complexe unit tests die je niet meer hoeft te schrijven, dat scheelt enorm in het totaal. Geheugenveiligheid is een lastig probleem en de meeste beveiligingsproblemen vandaag de dag hebben er nog steeds hun oorsprong in te vinden.

Dat memory leaks in Rust bestaan is nogal wiedes, dat geldt natuurlijk voor iedere taal waar je dynamisch geheugen kan toewijzen.

Overigens zijn cyclische referenties maken in Rust heel lastig juist door de borrow checker. Dit zorgt ervoor dat Rust geen garbage collector heeft, ondanks dat je niet zelf je allocaties bij hoeft te houden. Als je het echt wilt, kun je het voor elkaar krijgen met unsafe code (maar daar maak je het dan ook zelf naar) en met typen die de borrow checks tijdens runtime uitvoeren (wat ten koste gaat van de snelheid, en doorgaans als bijwerking heeft dat je de verwijzing niet meer kan aanpassen). Als je normale Rust schrijft, hoef je er geen rekening mee te houden.

Go is populairder dan Rust omdat het veel binnen Google wordt gebruikt, verder kan ik echt geen reden bedenken. De taal bevindt zich ergens in een grijs gebied tussen Bash, Python en C. De taal heeft na jaren mokken nog maar pas generics geïmplementeerd en er zitten allerlei eigenaardigheden in om te zorgen dat de compiler je broncode snel kan verwerken (wat ook het doel van de taal is) die in mijn ogen onhandig zijn voor programmeurs. Ik vind het zelf niet echt een geweldige taal, maar meningen verschillen. Als je algoritme veel bomen gebruikt, zou ik ook zeker niet eens proberen om Rust erbij te betrekken.

Overigens is een array-boom niet zo heel inefficiënt, afhankelijk van je eisen en implementatie is hij juist sneller doordat je meer relevante data in de cache lines kan laten. Een heap is tenslotte ook gewoon een binaire boom die op een array wordt geïmplementeerd en ieder geheugenallocatiesysteem maakt er wel ergens gebruik van. Voor een ongebalanceerde zoekboom kan het een prima oplossing zijn, die ook nog eens een stuk makkelijker veilig te krijgen is.
https://en.m.wikipedia.org/wiki/Binary_tree

This method benefits from more compact storage and better locality of reference, particularly during a preorder traversal. However, it is expensive to grow[citation needed] and wastes space proportional[citation needed] to 2h - n for a tree of depth h with n nodes.

En een managed taal heeft toch geen memory leaks? En gebruikt wel dynamisch geheugen

[Reactie gewijzigd door wkleunen op 1 januari 2021 21:46]

Rust is geen managed taal. Overigens hebben managed talen ook te maken met memory leaks als je referenties naar objecten vergeet weg te halen.
Als je een referentie naar een object hebt, dan is het toch geen leak ?
In het geval van complex genoege cyclische referenties kun je in een managed taal geheugen lekken doordat de garbage collector niet meer weet wat hij met je geheugen aan moet. Dit kan in complexe cyclische bomen nog wel eens voorkomen, dan kun je of een hele trage garbage collector krijgen (want die moet alle referenties checken) of je krijgt geheugen dat gelekt wordt.

Het gebeurt in de praktijk amper natuurlijk, maar ik heb het zelf wel eens per ongeluk veroorzaakt.
Nee, een cyclische referenties die niet bereikt kan worden vanuit de garbage collector root wordt gewoon opgeruimd. Kun je zo complex maken als je wil, maar de garbage collector werkt echt wel, ook als de referenties cyclisch zijn.

https://stackoverflow.com...m%20at%20its%20own%20root.

Een taal als python gebruikt een garbage collector naast reference counting om cycles op te ruimen
.
https://rushter.com/blog/python-garbage-collector/

[Reactie gewijzigd door wkleunen op 2 januari 2021 15:00]

Ik vergelijk wel eens Rust met een Elektrische auto. De eerste investering qua tijd is hoger, de totale tijd lager. Ik denk dat Rust betreft Total Cost of Ownership van je stuk software dat je schrijft een stuk lager zou liggen dan o.a. C / C++ / Java / C# en vele andere talen.
Ja, de compiler is trager, ja de eerste investering is een stukje hoger. Maar de Total Cost of Ownership voor een bedrijf om hun software in Rust te schrijven, zal waarschijnlijk in de kort toekomstige scenario's stukken lager zijn dan als je de software zou schrijven in een andere taal.
Precies dat. Ik heb een persoonlijk project in Rust geschreven dat normaal in C zou worden geschreven (een schaakprogramma). Ondanks dat ik goed kan programmeren in C (ook multi-threaded), heeft de compiler me toch een paar keer op de vingers getikt... en na enige analyse bleek dan inderdaad dat hetgeen ik aan het doen was meestal wel, maar niet in ALLE gevallen veilig was.

Zelfs als je goed kunt programmeren in een low-level taal als C, kun je heel snel dingen over het hoofd zien, zeker als het programma multi-threaded is. Het is dan prettig als de compiler je dan kan vertellen dat je onveilig bezig bent, anders zit je voor je het weet met een Heisenbug.
En toch is volgens het Security team van Microsoft 70% van alle CVE's van Microsoft software te wijten aan memory issues: https://msrc-blog.microso...ems-programming-language/.
Good programmers avoid unsafe practices anyway
Je hebt gelijk: hij die nooit fouten maakt kan in elke taal foutvrij programmeren!

Natuurlijk een nutteloze uitspraak, maar geen haar tussen te krijgen :)

[Reactie gewijzigd door 84hannes op 1 januari 2021 14:00]

Gefeliciteerd en gelukkig nieuwjaar voor het team van Rust. Rust is een mooie nieuwe taal, dat veel problemen uit het verleden weg haalt, zoals memory leaks. Het zorgt uiteindelijk voor veilige code. Qua performance blijf ik voorlopig C++ gebruiken, omdat ik echt elke milliseconds nodig heb in mijn project. Dan is juist fijn als je volledige controle heb hoe je data wordt opgeslagen. Je moet 6x nadenken voordat het uitrolt, want elke memory issue is er 1 teveel. Maar voor beginners is Rust wel een fijne taal om mee te beginnen i.p.v C++.

[Reactie gewijzigd door Xieoxer op 1 januari 2021 11:23]

Memory leaks bestaan nogsteeds in Rust. De checker controleert alleen of geheugen toegang veilig is, een geheugen leak is wel veilig.

http://huonw.github.io/bl...ry-leaks-are-memory-safe/

[Reactie gewijzigd door wkleunen op 1 januari 2021 11:53]

Natuurlijk zal het in een bepaalde vorm blijven bestaan. Maar het is al 100x beter dan bij C++.
Nee hoor. Zowel c++ als rust gebruiken het raii concept en eventueel reference counting. Dat is hetzelfde.
Hoe kan het dan dat er zoveel problemen zijn met memory in c++? Waarom kan ik in Rust een programma schrijven wat gewoon direct werkt zonder dat er allemaal "onverklaarbare" dingen gebeuren? C++ is gewoon verschrikkelijk om te gebruiken.
Ja, dat is dus memory safety wat jij noemt. Maar een memory leak is wel safe. Je programma crasht er niet door.

Misschien eerst even het artikel lezen wat ik gelinked hebt?
Wat jij zegt doet het lijken alsof C++ niet slechter is dan Rust. Ik snap dat memory leaks memory safe zijn, er raakt niets corrupt en er wordt niets gemanipuleerd. Wat niet memory safe is is C++.
Enige wat ik zeg is dat als je verwacht dat Rust gaat voorkomen dat er geen memory leaks zijn, dat je dan van een koude kermis thuis komt. Daar is de checker niet voor bedoelt, maar het is wel een veel voorkomende misvatting. Vandaar dat ik er op wijs.
Daar is de checker niet voor bedoelt
Als je modern c++ schrijft, zonder het keyword new te gebruiken, dan hoef je ook nooit delete te gebruiken (aan malloc en free ga ik geen woorden vuil maken). Het aantal memory leaks is daardoor volgens mij aanzienlijk minder (al durf ik afwezigheid niet te garanderen). Bij Rust bestaat delete niet eens dus kan het het per definitie niet vergeten. Dus zelfs al garandeert Rust de afwezigheid van leaks niet, voor zover ik kan bedenken reduceert hij ze wel.
Ja inderdaad. Maar modern c++ en rust gebruiken daarin allebei dezelfde methodiek, namelijk raii. Daarin zijn beide talen hetzelfde.

[Reactie gewijzigd door wkleunen op 1 januari 2021 14:19]

Klopt. Hiervoor geldt feitelijk wat @Grimm al stelt: een perfecte programmeur schrijft in elke taal perfecte code. Maar bij C++ moet je als ontwikkelaar zelf leren wat ‘modern’ is. Ik denk dat grofweg de helft van de C++-code die ik beroepsmatig tegenkom nog C met classes is; overal pointers, handmatige allocatie en RAII is ver te zoeken.

Ik hink op twee gedachten: ik vindt het prachtig wat er met moderne C++-versies allemaal mogelijk is, maar anderzijds vermoed ik dat je soms alle oude troep moet verbranden en iets moois nieuws moet bouwen.
Ja, C++ is ook eigenlijk niet 1 taal. Je kunt modern C++ programmeren, maar voor embedded / microcontrollers wordt nog vaak handmatige of statische allocatie gebruikt. Het zou mooi zijn als je vanaf 0 kunt beginnen, maar het feit is dat er heel veel C en C++ code nogsteeds "ligt". Ook zijn er heel veel ontwikkelaars die inderdaad programmeren op de jouw genoemde manier, pointers, handmatige allocatie. Probleem is dat zij gewoon geen kaas hebben gegeten van ownership. Het probleem zit hem dus in die ontwikkelaars, en niet in de talen. Als jij zegt van: we gaan alles in Rust programmeren, gaan ze stukken unsafe code toevoegen omdat ze in gevecht raken met borrow checkers (want ze snappen de ownership niet). Of dan toch nog stukken in C/C++ ontwikkelen, omdat dat gewoon makkelijker is. Daarom is er ook zo'n enorme verschuiving geweest naar managed talen (java, c# en alle script talen). De problemen daar met geheugen zijn minder groot, waardoor dat soort ontwikkelaars toch enigzins productief bezig kunnen. Security problemen in web gebaseerde software echter, zijn dan weer talrijk. Verschuiving voor dat soort ontwikkelaars gaat dan ook steeds meer naar low-code en hogere orde programmeertalen. Deze ontwikkelaars gaan niet weg, dus je moet de impact van hun fouten managen.
Als jij zegt van: we gaan alles in Rust programmeren, gaan ze stukken unsafe code toevoegen omdat ze in gevecht raken met borrow checkers (want ze snappen de ownership niet).
Ik denk dat je niet helemaal begrijpt wat unsafe doet.
Every once in a while, someone will talk about unsafe in Rust, and how it “turns off the borrow checker.” I think this framing leads to misconceptions about unsafe and how it interacts with safe code.
https://steveklabnik.com/...he-borrow-checker-in-rust

unsafe staat je toe bijvoorbeeld geheugenadressen direct te benaderen. Dereferencing dus.
Waarom zegt dan de manual:
https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html

It’s important to understand that unsafe doesn’t turn off the borrow checker or disable any other of Rust’s safety checks: if you use a reference in unsafe code, it will still be checked. The unsafe keyword only gives you access to these five features that are then not checked by the compiler for memory safety. You’ll still get some degree of safety inside of an unsafe block.

En:
the intent is that as the programmer, you’ll ensure the code inside an unsafe block will access memory in a valid way.

En:

he downside is that you use it at your own risk: if you use unsafe code incorrectly, problems due to memory unsafety, such as null pointer dereferencing, can occur.

Bijvoorbeeld het aanpassen van een static variable kan een race conditie veroorzaken. Alleen safe rust kan geautomatiseerd bewijzen dat je geen race condities hebt. Gebruik je unsafe code om een static aan te passen, is het de verantwoordelijkheid van de ontwikkelaar om te zorgen dat het race conditie vrij is.

Ik zou zeggen, doe dat dan niet. Gebruik dan geen static, dan hou je je formeel bewijs.

Je verliest niet alle checks inderdaad, maar toch wel een deel.

[Reactie gewijzigd door wkleunen op 1 januari 2021 22:17]

Ik mis je punt. Jij lijkt te suggereren dat unsafe de borrow checker uitschakeld. Zijn we het er over eens dat dat een onjuiste aanname is?
Unsafe schakelt toch een deel van de checks uit en effectief wordt het toch mogelijk om volledig de borrow checkere te omzeilen? Bijvoorbeeld data-races en null pointer dereferences worden niet meer gevalideerd ? Bovendien ook ownership wordt toch niet meer gecontroleerd ? Wel in de Rust code, maar als ik een C functie aanroep vanuit C, dan kan ik toch alles doen in die C code wat ik wil ? In de C code wordt toch geen borrow checking gedaan ? of mis ik iets ?

In jouw link staat toch ook:
It’s true that you have to do a lot more work when writing unsafe, since you don’t have the compiler helping you in certain situations, but that’s only for the unsafe constructs.

Het is een beetje flauwe discussie. Ok prima, de borrow checker staat niet uit, alleen een deel van de checks staat uit. Net als een lamp die kapot is, die kan soms ook aan staan, maar geen licht meer geven.

Wat ik zeg is: als je een team van onervaren software ontwikkelaars hebt die in rust gaan programmeren. Wees er dan beducht op dat zij stukken unsafe code toe gaan voegen om dingen werkende te krijgen. Ook zaken die gewoon in rust safe code kunnen, alleen om dat zij het niet goed werkende krijgen in safe code omdat ze het niet begrijpen, vallen ze terug op unsafe code om van die vervelende errors van de borrow checker af te komen.

Maar als jij vindt, de borrow checker staat in unsafe code ook gewoon aan, en het is prima om daarvoor blokken unsafe te gebruiken voor zaken die ook gewoon in safe kunnen, dan moet jij dat vooral doen.

Maar lees ook even:
https://www.ralfj.de/blog.../the-scope-of-unsafe.html

Daar staat ook: There used to be claims on the interwebs that “if a Rust program crashes, the bug must be in some unsafe block”. (And there probably still are.) Even academic researchers working on Rust got this wrong, arguing that in order to detect bugs in data structures like Vec it suffices to check functions involving unsafe code.

Het is dus niet voldoende om alleen de unsafe code blokken te controleren

En lees ook: https://cs.stanford.edu/~aozdemir/blog/unsafe-rust-syntax/

30% van de crates heeft unsafe code en closures worden niet unsafe gemarkeerd. Realiseer ook even dat het vooral ervaren ontwikkelaars zijn die nu met rust werken.

[Reactie gewijzigd door wkleunen op 2 januari 2021 09:01]

Maar als jij vindt, de borrow checker staat in unsafe code ook gewoon aan, en het is prima om daarvoor blokken unsafe te gebruiken voor zaken die ook gewoon in safe kunnen, dan moet jij dat vooral doen.
Als je mij kunt vertellen waar ik dat lijk te zeggen dan kan ik mijn tekst verbeteren. Ik zou namelijk wel gek zijn om dat te menen.

Ik stel slechts dat je niet bang hoeft te zijn dan ontwikkelaars ‘unsafe’ gaan gebruiken om de borrow checker te omzeilen, net zo min als je bang hoeft te zijn dat Israël atoomwapens zal gebruiken om Iran te bespioneren. Het is niet zo dat atoomwapens in mijn ogen veilig zijn, maar ze kunnen simpelweg niet voor dat doel misbruikt worden.

De kritiek die jij op Rust lijkt te willen geven gun ik je; zonder kritiek wordt niets beter. Maar daarvoor is het niet nodig mij woorden in de mond te leggen.

[Reactie gewijzigd door 84hannes op 2 januari 2021 12:20]

Wat programmeertaal betreft, inderdaad een goede ontwikkelaar kan in elke taal productief zijn. Echter de productiviteitsverschillen tussen ontwikkelaars onderling is enorm. Ik hoorde ooit iemand zeggen dat uit onderzoek bleek dat een goede ontwikkelaar 20x meer productief is, dan een slechte ontwikkelaar. Welk onderzoek dat was, en of die factor 20 klopt, dat moet je met een korrel zout nemen. Maar dat er echt grote verschillen zitten tussen ontwikkelaars, dat weten mensen met enige ervaring uit de praktijk wel.
Bij Rust bestaat delete niet eens dus kan het het per definitie niet vergeten.
std::mem::drop()

Ik gebruik dat soms om een mutex te droppen als ik die niet meer nodig heb. Soms komt het voor dat een struct die door verschillende threads gebruikt wordt, met lock() moet worden geblokkeerd. Dat levert een MutexGuard op, waardoor andere threads de struct niet meer kunnen gebruiken.

Je hoeft deze MutexGuard zelf niet vrij te geven, maar dat is niet altijd handig. Stel dat je een berekening wil maken op de inhoud van struct X. Als je de struct X gelocked laat zodat die niet verandert en je ermee kunt rekenen, dan kunnen andere threads er niks mee doen (behalve lezen).

Het kan sneller zijn om de struct te locken, hem te clonen naar je lokale scope, dan met std:mem:drop() de MutexGuard weer te droppen en verder te rekenen met je lokale kopie.
Dan kun je misschien beter een clone() functie maken, die een clone van je struct maakt en returned. Dan hoef je niet elke keer handmatig de lock vrij te geven.
Maar drop() doet niets dat niet even goed zou gebeuren: iedere variabele wordt verwijderd aan het einde van zijn scope. De implementatie van drop is dan ook doodsimpel: {}. drop() speelt volgens mij geen rol van betekenis in het voorkomen van memory leaks.

[Reactie gewijzigd door 84hannes op 2 januari 2021 12:11]

Nee, klopt; maar ik denk dat je mijn bericht niet helemaal begrepen hebt.

Stel je hebt een functie die in zijn eigen thread draait. Hieronder probeer ik het te verduidelijken met pseudo-code.

=====
{
mtx_guard = foo.lock(); <= vanaf dit punt kunnen andere threads "foo" niet meer gebruiken. Andere threads komen in queue terecht asl zij "foo" ook proberen te locken.

----
let x = 0;
// hele lange berekning
// uitkomst: x is nu 42.
----

// draad eindigt hier. de "JoinHandle" van de draad bevat nu "42". Hier wordt de mtx-guard vrijgegeven.
}
=====

Je houdt op deze manier "foo" geblokkeerd voor andere threads, tijdens de lange berekening. Als deze berekening zwaar is (grote kans, anders zou hij niet in zijn eigen thread hoeven te zitten) dan is dit een betere optie, zeker als de struct niet groot is:

=====
{
mtx_guard = foo.lock(); <= vanaf dit punt kunnen andere threads "foo" niet meer gebruiken. Andere threads komen in queue terecht asl zij "foo" ook proberen te locken.

let local_foo = mtx_guard.clone(); <= de mtx_guard "weet" dat hij niet zichzelf moet clonen, maar het object dat door hem gelocked wordt. "local_foo" is nu een thread-local kopie van "foo"

std::mem::drop(mtx_guard); <= hier wordt de guard gedropped, zodat andere threads "foo" kunnen gebruiken. Verderop maak je gebruik van "local_foo" om je berekening af te maken.

----
let x = 0;
// hele lange berekning
// uitkomst: x is nu 42.
// stop x in de "JoinHandle" van de thread zodat deze waarde wordt teruggegeven als de thread eindigt.
----

// draad eindigt hier. de "JoinHandle" van de draad bevat nu "42".
}
=====

Hetzelfde geldt als je bijvoorbeeld "foo" moet locken, om enkel een waarde uit te lezen, en dan een heel lang stuk zware code uitvoert waarin je "foo" niet meer nodig hebt. Dan is het onnodig om "foo" gelocked te houden tijdens dat stuk code, en kun je de lock beter meteen droppen na het lezen van de waarde.

Dus ja, je hebt gelijk; std::mem::drop() voorkomt geen geheugenlekken of iets dergelijks, maar het is enkel een manier om dingen zoals locks en geheugenvretende variabelen sneller vrij te geven dan helemaal aan het eind van de scope, als je weet dat je de betreffende dingen niet meer nodig hebt.

[Reactie gewijzigd door Katsunami op 2 januari 2021 15:08]

Je hebt gelijk, maar dat was niet het onderwerp :)
Bij c moet je af en toe malloc gebruiken en dus free aanroepen om geheugen vrij te geven.
Bij C++ kan je new gebruiken; dan moet je delete gebruiken om geheugen vrij te geven; tevens wordt dan de destructor aangeroepen.
Bij Rust kan het gebeuren dat je middels drop de destructor aanroept, maar om geheugen vrij te geven is dat eigenlijk nooit nodig.
Klopt, maar dan nog is het zo dat std::mem::drop() effectief hetzelfde doet als "delete" in C++: het ruimt iets op dat je niet meer nodig hebt. Wel heb je gelijk dat je in C++ altijd new en delete als combinatie nodig hebt. Als er dingen in één scope worden aangemaakt en verwijderd, dan is dat geen probleem, dan kun je gewoon aan het begin van de scope "new" gebruiken, en aan het eind van de scope "delete".

Het gevaar zit hem in de functies die pointers retourneren: dan moet je als programmeur zelf bijhouden welke objecten er in je programma rondzwerven en ze op de juiste momenten vrijgeven. Als je dat vergeet, dan heb je een geheugenlek. Dat kan in Rust als het goed is niet meer voorkomen.

In Rust is het mogelijk om referenties terug te geven, maar dat is niet triviaal: dan moet je gaan werken met lifetimes. De compiler kan namelijk niet zelf bepalen dat een object lang genoeg blijft bestaan als je een referentie teruggeeft (als de functie eindigt, gaat het object out of scope, en wordt de referentie ongeldig).

Met lifetimes kun je dan voor de compiler bewijzen dat je code zo is gestructureerd dat het object nog steeds bestaat op elk moment dat de referentie wordt gebruikt. Zoals gezegd, dat is echter niet triviaal, en voor Rust 2018, was dat een -enorm- struikelblok. De borrow checker in Rust 2018 is -veel- slimmer dan die in Rust 2015: zeer veel van de lifetimes die je in Rust 2015 nodig had om de borrow checker te overtuigen dat je code klopt, heb je niet meer nodig in Rust 2018.

Als je een fractie snelheid inboet, kun je de rest van de referenties ook nog elimineren met het moven (verplaatsen) van een variabele van de ene naar de andere, of als het écht niet anders kan, met een clone(). Als je echt de laatste druppel snelheid nodig hebt kun je echter nog steeds met referenties en lifetimes werken, of zelfs met unsafe code als je fratsen met het geheugen wil uithalen die Rust gewoon simpelweg niet toestaat.

[Reactie gewijzigd door Katsunami op 2 januari 2021 16:43]

Als er dingen in één scope worden aangemaakt en verwijderd, dan is dat geen probleem, dan kun je gewoon aan het begin van de scope "new" gebruiken, en aan het eind van de scope "delete".
Als het allemaal zou eenvoudig is zou ik de stack gebruiken; er zijn weinig redenen om in deze situatie manueel geheugen te beheren.
Qua performance blijf ik voorlopig C++ gebruiken, omdat ik echt elke milliseconds nodig heb in mijn project.
Als iemand die op dagelijkse basis met C++ werkt en uitgebreid met Rust heeft geexperimenteerd vraag ik me af welke use-case voor jou trager werkt in Rust dan in C++. Ik heb praktisch geen verschillen kunnen meten, en ook aan de hand van wat ik online kon vinden produceert Rust binaries die vergelijkbaar presteren met in C geschreven software.
welke use-case voor jou trager werkt
Compilen? :)

(Geen idee hoe traag g++ e.d. zijn hoor, maar ik weet wel dat ik rustc niet bepaald chill vind qua compile times voor snel iteratief programmeerwerk)
Grapjas :+

Maar voor snelle compile-times ga je ook niet naar C++, nee.
Maar voor snelle compile-times ga je ook niet naar C++, nee.
Toch is naar mijn ervaring Rust nog een slag trager. Je krijgt er veel voor terug, maar frustrerend is het wel.
In mijn ervaring was dat inderdaad zo, maar inmiddels niet meer. Er is ook al twee jaar hard gewerkt aan de prestaties van de compiler.
Ik heb er over gelezen maar recent weinig mee gespeeld dus ik moet je op je woord geloven.
> . Qua performance blijf ik voorlopig C++ gebruiken, omdat ik echt elke milliseconds nodig heb in mijn project. Dan is juist fijn als je volloge controle heb hoe je data wordt opgeslagen.

Je hebt die controle ook volledig bij Rust.
Rust is vaak toch ook wel sneller. Kijk maar naar de benchmarks.
Benchmarks != Prestaties in dagelijks gebruik
Qua performance blijf ik voorlopig C++ gebruiken, omdat ik echt elke milliseconds nodig heb in mijn project.
Misschien is dan profilen en selectief assembly (desnoods via intrinsics) toepassen een goede zet...
Grapjas. Rust's compiler gebruikt LLVM als backend, net als Clang. Zowel Rust als Clang vertalen naar LLVM's Intermediate Representation, en van daar neemt LLVM de verdere compilatie over. Als je code schrijft in C (of C++) die sneller is dan vergelijkbare code in Rust, dan is je Rust-code brak.

En Rust is helemaal geen handige taal voor beginners. C++ ook niet overigens. Beiden zijn heel lastig om mee te beginnen, maar om verschillende redenen. Als je niet precies weet wat je aan het doen bent qua geheugengebruik, dan loop je bij Rust tegen een muur op (de "borrow checker").... bij C++ -lijkt- alles in eerste instantie te werken, maar daar kom je (zonder dat je dat als beginner weet) in een mijnenveld terecht.


Om te kunnen reageren moet je ingelogd zijn


Apple iPhone 12 Microsoft Xbox Series X LG CX Google Pixel 5 Sony XH90 / XH92 Samsung Galaxy S21 5G Sony PlayStation 5 Nintendo Switch Lite

Tweakers vormt samen met Hardware Info, AutoTrack, Gaspedaal.nl, Nationale Vacaturebank, Intermediair en Independer DPG Online Services B.V.
Alle rechten voorbehouden © 1998 - 2021 Hosting door True