Door Dustin Hendriks

Freelanceredacteur

Rust voor wie aan veiligheid hecht

Eerste stappen met programmeertaal Rust

13-04-2022 • 06:00

69

Multipage-opmaak

Inleiding

Met dit artikel helpen we je op weg bij het programmeren met de taal Rust. We leggen kort uit wat Rust is en waarin de programmeertaal zich onderscheidt, we geven aan wat je nodig hebt om aan de slag te gaan, en lichten het framework Good Game Easily uit, waarmee je een snelle start kunt maken.

RustRust is een algemene programmeertaal, begonnen door Graydon Hoare, als zijproject binnen de afdeling Mozilla Research. In 2009 begon Mozilla het project te sponsoren. De naam verwijst naar bepaalde schimmels uit de klasse van roesten en is een verwijzing naar robuust. Tijdens de ontwikkeling van Mozilla's Servo-engine werd de taal geoptimaliseerd en in 2015 verscheen versie 1.0. Sindsdien verschijnt er elke zes weken een nieuwe release.

De groei en toenemende populariteit van Rust maakten dat het project binnen Mozilla tegen grenzen aan liep. Daar kwam bij dat Mozilla in 2020 250 medewerkers ontsloeg vanwege de gevolgen van de coronacrisis en het uitblijven van succesvolle betaalde diensten. Onder hen waren ook Rust-medewerkers. Het Rust Core Team en Mozilla brachten Rust daarom onder in een stichting, waaronder de verschillende merkrechten en domeinnamen rond Rust en packet manager Cargo zouden vallen, evenals de financiële verplichtingen die hiermee gemoeid zijn. Als onafhankelijk project moest Rust ook meer investeringen aantrekken, was de bedoeling.

Rust is een programmeertaal die gericht is op prestaties, betrouwbaarheid en productiviteit, en die onder andere door Mozilla, Discord en Microsoft wordt ingezet. De taal richt zich op het maken van snelle en robuuste applicaties, met ondersteuning voor multi-threaded concurrency, oftewel gedistribueerd annex parallel programmeren. Dit kan de prestaties van programma's ten goede komen.

In de afgelopen jaren is Rust populairder geworden onder ontwikkelaars, volgens de Tiobe-index. De taal staat momenteel op plaats 26 in de ranglijst, tussen Cobol en Prolog. De verwachting is dat Rust voorlopig in populariteit blijft stijgen.

Applicaties met een noodzaak voor hoge prestaties worden vaak geschreven in C of C++. Deze programmeertalen zijn snel, maar vatbaarder voor fouten door de programmeur. Zo is er beperkt automatisch geheugenbeheer aanwezig. Bij C en C++ ligt de verantwoordelijkheid hiervoor bij de programmeur, wat het risico op fouten in applicaties vergroot. Rust is ontworpen met de ideologie om veiligheid te forceren vanuit de taal, met zo weinig mogelijk gevolgen voor de prestaties. Het is daarom vooral bedoeld als substituut voor C en C++.

Onder de motorkap

Rust is een gecompileerde taal. Hierbij wordt broncode rechtstreeks vanuit de doelmachine vertaald in een uitvoerbaar programma. Op een ander systeem hoeft bij het starten van een uitvoerbaar bestand daarom geen Rust geïnstalleerd te worden.

Geheugenbeheer

Veel programmeertalen werken aan de hand van objecten. Een object kan worden gezien als een container die zowel data als logica kan bevatten. Een object kan bijvoorbeeld een vierhoek zijn. Data binnen dit object kan hypothetisch de coördinaten van de hoekpunten bevatten. Mogelijke logica binnen een vierhoek kan bijvoorbeeld verifiëren of er sprake is van een vierkant, rechthoek of parallellogram.

Object Encapsulatie [9778]

Veel programmeertalen maken gebruik van een garbage collector. Bij automatisch geheugenbeheer probeert de garbage collector geheugen vrij te geven als dat in gebruik is door objecten die niet meer in de applicatie worden aangeroepen. Het principe functioneert daarmee volgens de stappen:

  1. Indexeer objecten die niet meer benaderd zullen worden.
  2. Geef het geheugen van deze objecten vrij.

C noch C++ beschikt over een garbage collector. Dit wordt bij C en in veel gevallen ook bij C++ handmatig opgelost binnen het programma. Dat resulteert in een potentieel zeer snel programma, maar de foutgevoeligheid is groter. Als er fouten worden gemaakt bij het opruimen, kan er sprake zijn van een geheugenlek. Dan kan het geheugen niet correct worden opgeruimd en blijft de grootte van het programma oplopen. De garbage collector is in andere programmeertalen geïntroduceerd om deze verantwoordelijkheid bij de programmeur weg te halen. De ontwikkeltijd van gelijkwaardige programma's is daardoor over het algemeen korter, maar de prestaties kunnen hierdoor minder zijn.

Bij Rust ontbreekt net als bij C en C++ een garbage collector. Dit is binnen Rust opgelost door het introduceren van het principe van ownership. Onder de motorkap worden hierbij referenties naar objecten bijgehouden. Als deze referenties buiten bereik raken, worden objecten automatisch opgeruimd en kan geheugen worden vrijgegeven. Om dit mogelijk te maken, forceert Rust het programmeeridioom resource acquisition is initialization, of raii. Raii onderscheidt zich van een garbage collector doordat er geen sprake is van een afzonderlijk proces, dat het geheugen misschien niet op het ideale moment zal vrijgeven. Als je objecten inkapselt en strikt koppelt met het aanmaken en vrijgeven van geheugen bij het construeren respectievelijk afbreken, hoef je niet handmatig op te ruimen. Het geheugengebruik hangt daarom samen met de levensduur van objecten. Dit resulteert in een lagere foutgevoeligheid dan bij het handmatig opruimen van geheugen, zonder dat het gevolgen heeft voor de prestaties van een ontwikkeld programma.

Object RAII [9778]

Rust kan als moeilijk worden ervaren vanwege dit principe van ownership, waarbij het goed omgaan met geheugen geforceerd is vanuit de taal. Dit kan worden omschreven aan de hand van de volgende regels:

  • Iedere variabele heeft één eigenaar.
  • Iedere waarde heeft gelijktijdig maximaal één eigenaar.
  • Bij het buiten bereik raken van de eigenaar worden toegekende waarden weggegooid.

Geheugenveiligheid

Rust is ontworpen om 'geheugenveilig' te zijn; de taal staat geen null pointers, dangling pointers of data races toe. Dit kan worden toegelicht aan de hand van de volgende eisen, die worden geforceerd door het model van ownership:

  • Er moet altijd een correcte waarde toegekend zijn aan geheugenadressen.
  • Waarden in het geheugen moeten overeenkomen met een vooraf gespecificeerd type.
  • Conflicterende operaties van het schrijven en/of lezen op geheugenadressen zijn niet mogelijk.

Configureren van de ontwikkelomgeving

Om gemakkelijk en snel zonder eigen ontwikkelomgeving te kunnen experimenteren met Rust, is de Rust Playground gemaakt. Dit is een relatief eenvoudige online-editor, geschikt voor het experimenteren met code.

Rust Playground [9778]

De instructies voor een lokale installatie van Rust kunnen worden gevonden op rust-lang.org/tools/install. Hier vind je de installer 'rustup', die ook het updaten van installaties mogelijk maakt.

Install Rustup [9778]

De installatie van rustup kan worden aangepast via een aantal opties die worden weergegeven in het geopende venster. Daarbij hebben wij gekozen voor de standaardinstallatie (1). Na de installatie van de toolchain-installer kan in powershell of command prompt het commando 'rustup' worden ingetypt en uitgevoerd om te verifiëren dat de installatie gelukt is.

Verify Rust Toolchain [9778]

Er zijn verschillende mogelijke ontwikkelomgevingen, of ide's, om uit te kiezen. Dit artikel beschrijft het configureren van een ontwikkelomgeving voor Rust-development. Daarbij behandelen we twee opties: Visual Studio Code in combinatie met de Rust-plug-in en Atom gecombineerd met de rust-analyser-plug-in.

Visual Studio Code

De aangeraden optie betreft Visual Studio Code samen met Rust-support for Visual Studio Code. Deze ontwikkelomgeving is snel in te richten en gratis in gebruik.

Na de installatie van Visual Studio Code kan de Rust-plug-in worden geïnstalleerd.

VSCode Install Rust [9778]

Atom

Een alternatieve optie is het gebruik van Atom in combinatie met ide-rust. Deze configuratie kost meer tijd dan de Visual Studio Code-omgeving.

Om de installatie van ide-rust compleet te maken, moet nog de rust-analyser worden geïnstalleerd. Dit is een modulaire frontend voor Rust.

Install Rust Analyser [9778]

Tot slot moet het pad naar de executable 'rust-analyser.exe' worden toegevoegd aan Path, via het aanpassen van de omgevingsvariabelen.

Set Environment Path [9778]

Door de installatie van de plug-in en rust-analyser is er een complete ontwikkelomgeving opgezet met zoeksuggesties: IntelliSense.

Aanmaken van een nieuw project

Een nieuw testproject 'Hello World' kan worden aangemaakt via Cargo. Cargo is de package manager van Rust en kan gebruikt worden voor het bouwen, draaien en beheren van Rust-projecten. Deze tool is standaard geïntegreerd in de toolchain-installer van Rust: rustup. Hiervoor is om deze reden geen extra installatie nodig. Het commando cargo new <project naam> --bin kan worden uitgevoerd voor het aanmaken van een nieuw project.

Cargo Create Project [9778]

Nadat je naar de projectfolder bent genavigeerd via cd RustHelloWorld, kan het project uitgevoerd worden met cargo run. Zoals hieronder weergegeven verschijnt dan 'Hello, world!' op het scherm.

Rust Hello World [9778]

Deze projectfolder kan in zijn geheel binnen Visual Studio Code of Atom worden geopend, zodat je wijzigingen in de code kunt aanbrengen op een toegankelijke manier.

Atom Opened Rust Project [9778]

In de praktijk

Er zijn veel toepassingen waarvoor Rust ingezet kan worden. Om een snelle start te maken met Rust, kun je kijken naar het framework Good Game Easily, of ggez. Dit is een lichtgewicht bibliotheek die onder andere implementaties levert voor 2d-graphics, audio, fonts en gebruikersinvoer. Een voordeel van deze bibliotheek zijn de verschillende bijbehorende voorbeelden, waarbij de mogelijkheden van dit framework naar voren komen.

Deze bibliotheek is uitermate geschikt voor het bouwen van (2d-) games, in verband met de aanwezigheid van hardwareacceleratie en geavanceerdere grafische opties (shaders). Hardwareacceleratie betreft het gebruik van specifieke hardware, bijvoorbeeld een grafische kaart, om taken sneller uit te kunnen voeren. Dit leidt tot minder energiegebruik en een hoger aantal frames per seconde.

Dit framework kan direct worden gedownload van de onderstaande link of via het versiebeheersysteem GIT.

Git Clone Ggez [9778]

Na het binnenhalen van het framework kan een voorbeeldapplicatie gecompileerd en uitgevoerd worden. Een leuke optie is daarbij het spelletje Astroblasto, een compleet voorbeeld van de mogelijkheden van het gebruikte framework.

Rust Run Astroblasto [9778]

Na de invoer van het bovenstaande commando wordt het spel zichtbaar en geopend op het apparaat. In Astroblasto kan de speler rondvliegen met een schip en objecten vernietigen voordat die het eigen schip beschadigen. Daarbij wordt de invoer van het toetsenbord gekoppeld aan een actie van de speler, zoals vliegen, draaien of schieten. Intussen wordt hierbij audio afgespeeld.

Rust Play Astroblasto [9778]

De opzet van de game kenmerkt zich doordat deze relatief eenvoudig aangepast kan worden in de code, waarbij de basis van Astroblasto gevonden kan worden in '05_astroblasto.rs'.

Om de game eenvoudiger of moeilijker te maken, kunnen de levens van de speler en de omgeving worden gemanipuleerd op regels 73 tot en met 81.

Rust Modify Astroblasto Lives [9778]

De snelheden van de speler, kogels en objecten kunnen eveneens aangepast worden. Deze kunnen worden aangepast op regels 159 tot en met 168.

Rust Modify Astroblasto Speed [9778]

Bij het zoeken tussen de bronbestanden kunnen de plaatjes ook worden aangepast door het overschrijven van de afbeeldingen 'player.png', 'hot.png' en 'rock.png', die relevant zijn voor Astroblasto.

Rust Modify Astroblasto Images [9778]

Het resultaat is een spel waarbij de speler op een statische (gecentreerde) positie de vijanden van het speelveld moet verwijderen.

Rust Mod Astroblasto [9778]

Doordat er al relatief veel bibliotheken en voorbeelden voor Rust bestaan, kan voldoende ondersteuning gevonden worden. Daarnaast bieden bestaande (opensource-) projecten een laagdrempelige methode om te experimenteren met Rust en zo ervaring op te doen. Voordat je het weet, kun je als Tweaker bugs oplossen.

Tot slot

Rust is een krachtige programmeertaal met veel mogelijkheden. Het aspect waarin Rust in het bijzonder uitblinkt, is de veiligheid, die vanuit de taal wordt geforceerd. De gevolgen voor de prestaties zijn daarbij minimaal. Rust is om deze reden een alternatief voor C++, die veel pijnpunten van deze taal aanpakt. Geheugenveiligheid wordt in Rust gegarandeerd door ownership. Dat vergt tijd om te leren, maar kan tijdens het programmeren voordelen bieden ten opzichte van relatief onveilige talen zoals C en C++.

Rust is in de afgelopen jaren flink in populariteit gestegen en de verwachting is dat die populariteit nog zal groeien. Er bestaan inmiddels diverse plug-ins voor editors, zoals Visual Studio Code en Atom, die ervoor zorgen dat het installatieproces beperkt blijft en er direct genoten kan worden van voordelen als het automatisch aanvullen van code. Een bijkomend voordeel is de hoeveelheid publieke bibliotheken en voorbeelden. Hierdoor zijn het instappen in de taal en experimenteren relatief makkelijk, hoewel sommige principes van de taal een steile leercurve hebben.

In dit artikel hebben we een eerste start beschreven om met Rust aan de slag te gaan. Er is veel materiaal online te vinden waarvan je kunt leren en waarmee je verder kunt experimenteren. Wellicht heb jij al een mooi product gemaakt met Rust of ga je daar in de toekomst mee aan de slag. Laat het ons en je medetweakers weten in de comments.

Reacties (69)

Sorteer op:

Weergave:

De officiële documentatie van Rust is een zeer goede en uitgebreide tutorial:

https://doc.rust-lang.org/book/

En je kan daar tegelijkertijd Rustlings of Rust By Example mee doen, oefeningen om te kijken of je de taal goed doorhebt:

https://github.com/rust-lang/rustlings

https://doc.rust-lang.org/rust-by-example/index.html

[Reactie gewijzigd door Bas.Bas.Bas op 22 juli 2024 15:25]

Microsoft heeft ook een leuke Rust tutorial die ik kan aanraden:

https://docs.microsoft.co...n/paths/rust-first-steps/
Ik ben zelf hobbymatig actief met Rust op diverse vlakken.

Ik heb diverse ARM microcontrollers gekocht, NRF52850, STM32F401 en ESP32C2 (RISC-V). Tevens een ledstrip WS2812b ledstrip en probeer daar code op te schrijven.
Mijn doel was om Rust te leren en wat meer embedded ervaring op te doen.
RGB ledstrips zijn altijd leuk.

Mijn projectje bestaat uit ARM firmware om de ledscripts aan te sturen maar ook uit PC software om via USB je eigen patronen te sturen. Verdere doel is om Zigbee aan te praat te krijgen om via een afstandsbediening je patroon te kiezen. Maar Zigbee is wat lastig om snel te doorgronden en er zijn nog maar weinig Rust libraries.

https://github.com/vDorst/nrf-rs-smartled

Rust embbed book https://docs.rust-embedded.org/book/intro/index.html
Voor rust heb je diverse HAL lagen voor diverse microcontrolers:
Mijn gevoel wordt de STM32 het beste ondersteund.
• STM32: https://github.com/stm32-rs
• Atmel/Microchip: https://github.com/atsam-rs
• Norfic NRF: https://github.com/nrf-rs

Op mijn werk begin ik het ook al een beetje te gebruiken.
Voor een testkast heb ik een Python module geschreven in Rust met https://github.com/PyO3/PyO3

Ik vind het typesystem van Rust erg fijn, ik hou wel van strikte regels als het gaat om programmeren.
Rust wijst mij iig op mijn fouten. Verder probeer ik toch de moeite te nemen, hoe het op de Rust manier moet, in het geval dat Rust compiler mijn code weigert.

Verder is het fijn dat Rust cross-platform is.
Het gemakt om libraries te definiëren in de Cargo.toml en dat alles automagisch gaat.
Dus veel dingen kan je maken in Windows en draaien op je Linux server.

[Reactie gewijzigd door vDorst op 22 juli 2024 15:25]

Nadeel van Rust is dat er op dit moment geen goede UI frameworks zijn. Degene die er zijn zijn allemaal interops van C/C++ frameworks.

Native Rust UI frameworks zijn nog vrijwel allemaal in alpha of beta fase.
Klopt, het is nog vroeg dag. Dit is een interessant project met potentie. Het is opgezet door mensen met heel veel ervaring met Qt & QML.
Ik zie dat het voor meerdere programmeertalen beschikbaar is dus het is dan waarschijnlijk niet native Rust.
Dat is het mooie van Rust.
Omdat Rust vaak moet interfacen met andere talen is daar ook goed support voor.

Via C FFI en scripts om C/C++ bindings te maken of direct zoals Python Pyo3.

Een voorbeeld is de Signal App. Zij hebben een Signal Client Library in Rust en hebben glue-code/bind-gen zo dat het te integreren is met andere talen.
Zie: https://github.com/signalapp/libsignal
Dat weet ik. Maar meestal als ik zie dat het bindings heeft naar meerdere talen zit er C of C++ achter.

Ik ben wel bang dat als je een "universele" API maakt dat het teveel concessies doet aan een goede Rust API.
Pyo3 is inderdaad een goede. Gebruik het zelf of libraries te schrijven voor mijn Python code, op plekken waar hoge performance nodig is (al gauw 50x sneller dan python)
Maar als je gaat interfacen met andere talen verlies je mogelijk de veiligheidsvoordelen van Rust.
Ik heb dit ook ondervonden.

We spelen met vrienden af en toe een kaartspel Big2.
Iemand had dit gemaakt in zijn eigen programmeertaal en alleen voor Windows.
Omdat ik een Linux gebruiker ben en het spel niet onder Wine wilde draaien heb ik er een Rust CLI versie van gemaakt.
Tevens heb ik nog geprobeerd om daar een GUI/Webversie van te maken.
Maar een framework dat alles kan is zeer beperkt.
Ik heb wat succes gehad met egui maar de webversie vereist ook een eigen web gameserver.
Omdat ook te schrijven was voor mij nog te lastig en toen ben ik afgehaakt.
Dat is ook hetgeen waar ik tegenaan loop voor een applicatie die ik wil schrijven.

Daarom denk ik erover om de GUI maar te schrijven in Electron + een of ander front-end framework, met een Rust backend. (Deze backend bestaat al en die werkt op het moment samen met andere GUI's. Ik wil er echter een eigen GUI voor hebben; gewoon omdat het kan, c.q. dit project een hobby is, en ik normaal niet zoveel met front-ends doe. Het is dus ook een manier om op dat gebied mijn kennis weer wat op peil te brengen.)
Ben ook overgestapt op RUST nadat GO Garbage Collector mijn high availability applicatie steeds aan het freezen was voor een aantal seconden, omdat garbage collecting. RUST heeft een grote leercurve, maar als je eenmaal de logica snapt van de taal, is het een zeer behendige taal.
De impl{} blokken komen bij mij over als "classes" zoals in Go via structs en PHP met classes, is.
Het is wel tof om te zien hoe goed het functioneert onder hevige load. Momenteel krijgt mijn open source project iets van 6000 connecties per seconden op zijn dak, en het is mooi om te zien hoe Rust via WARP en tokio threads, uitmuntend functioneert.

Gaat tevens om dit project:
https://github.com/Power2All/torrust-tracker
Ik werk hier samen met een andere Nederlander aan, maar meerdere inzichten van verschillende hoeken zijn altijd welkom, maar is een mooi project voor beginners om enigszins inzicht te krijgen hoe RUST functioneert. Dit is tevens ook mijn eerste Rust project waar ik daadwerkelijk aan bijdraag :)

[Reactie gewijzigd door Power2All op 22 juli 2024 15:25]

Installeer alsjeblieft niet de Rust extensie in VSCode. Gebruik in plaats daarvan de Rust Analyzer plugin. 100x beter en de de facto standaard voor iedereen die Rust gebruikt.

De Rust plugin is oud en zeer beperkt in wat het kan. Rust Analyzer is de opvolger.
Zouden jullie niet die rust plugin willen aanbevelen. Rust analyzer is de betere plugin en wordt wel actief ontwikkeld. Het andere alternatief is IntelliJ met de IntelliJ Rust plugin.
Leuk om Rust zo in de spotlight te zien hier op Tweakers :)

Het artikel gaat kort in op dat Rust veelgemaakte programmeerfouten kan voorkomen. Maar welke fouten zijn dat zoal en hoe doet Rust dat? Ik schreef hier een tijdje terug over op mijn blog: https://polyfloyd.net/post/how-rust-helps-you-prevent-bugs/

En ook, hoe je Rust SQL injecties zou kunnen voorkomen: https://polyfloyd.net/pos...ention-of-sql-injections/
Heerlijk zo'n stuk, waar je na het lezen meteen zelf mee aan de slag wilt gaan :*)

Toevallig laatst Visual Studio gedownload, (Mijn zoontje wilde zelf een spel gaan maken) en het voorbeeld uit dit Tweakers artikel is precies wat ik zocht voor hem!
Rust is wel heel hardcore als je alleen een spel wilt gaan maken. Afhankelijk van de leeftijd zou ik eerder beginnen met Scratch, Game Maker of Unity.
Dan krijgt hij ook een introductie tot programmeren maar heeft ie er waarschijnlijk iets meer plezier in (veel snellere resultaten).

[Reactie gewijzigd door Wolfos op 22 juli 2024 15:25]

Mijn persoonlijke voorkeur voor Rust is Visual Studio Code (dus niet de oude Visual Studio waarnaar Microsoft hun nieuwe editor vernoemd heeft om mensen te verwarren) met de rust-analyzer-plugin. Ik vond de standaard Rust-plugin nogal matig als het op macro's en auto-aanvulling aankomt, en ook het debuggen wordt met deze extensie wat makkelijker in mijn ervaring.

Er zijn spellen gemaakt in Rust (ik geloof dat Veloren daarvan de grootse is) maar als beginner zou ik toch echt met C# + Unity of Game Maker Studio spelen voor ik Rust zou aanraden. Zelfs ervaren programmeurs hebben soms moeite met het leren van alle beperkingen en functionaliteiten die Rust te bieden heeft! Het begint allemaal zo heerlijk makkelijk, maar je zult je verbazen hoe snel je ruzie gaat krijgen met de borrow checker als je met de taal gaat spelen.
Zelfs ervaren programmeurs hebben soms moeite met het leren van alle beperkingen en functionaliteiten die Rust te bieden heeft! Het begint allemaal zo heerlijk makkelijk, maar je zult je verbazen hoe snel je ruzie gaat krijgen met de borrow checker als je met de taal gaat spelen.
Dat is juist het grappige: als je ruzie krijgt met de borrow-checker, dan weet je meteen dat, indien je dit programma in C of C++ hebt geschreven, een onveilig of crashend stuk software zou hebben gehad.

Ik heb een project in Rust geschreven en ik heb nauwelijks te maken gehad met de borrow-checker, totdat ik begon met threading. (Gewoon even een pointer vanuit de ene naar de andere thread sturen gaat het hem dus niet worden, zelfs niet als je die pointer veilig verstuurt en de struct waarheen die verwijst in een Mutex zit... het hele ding moet dan ook nog in een Arc gestopt worden.)

Ik moet wel zeggen dat ik sommige mogelijkheden van de taal weinig of niet gebruikt heb tot nu toe, simpelweg omdat ik ze niet nodig heb gehad (macro's) of de helft van de tijd het nut er niet van inzie (closures; die de code ingewikkelder te begrijpen maken op elke plek waar ik ze gebruik). Ik gebruik geen features enkel om features te gebruiken.

Soms moet ik zelfs op sommige plekken een feature laten schieten (in een geval, iterators) simpelweg omdat de feature heel veel langzamer is dan de ouderwetse manier (in dit geval, een simpele loop).

[Reactie gewijzigd door Katsunami op 22 juli 2024 15:25]

Mwah, veel data structuren zijn met eenvoudige locking-mechanismes wel veilig te krijgen in andere talen (std::mutex in C++ bijvoorbeeld) waar je in Rust soms toch echt even achter je oren moet krabben.

Het voordeel is wel dat je het bij Rust zelden verkeerd kan doen, waar een mtx.lock() vergeten bij C++ een reële optie is, maar ik zou niet direct zeggen dat concepten die door de borrow checker worden geweigerd inherent verkeerd zouden gaan. Ik moet zelf nog steeds een keer goed leren hoe je nou multithreaded mutable references doet in Rust, maar gelukkig maak ik er zo weinig gebruik van dat ik het pas hoef te Googlen als ik er weer tegenaan loop.

Pas ja veel stoeien met de borrow checker realiseer je je dat hij eigenlijk je vriend is, niet je vijand, maar ik denk dat iedere Rust-programmeur wel ooit tegen zijn compiler aan het vloeken is geslagen omdat aan de eisen voldoen moeilijker is dan je op het eerste gezicht zou denken :)
Pas ja veel stoeien met de borrow checker realiseer je je dat hij eigenlijk je vriend is, niet je vijand
De borrow-checker in combinatie met Rust-Analyzer is zo geweldig goed dat niet meer bang ben om mijn programma te refactoren. Ik pas simpelweg een functie aan, en de borrow-checker en Rust-Analyzer zeggen wat ik waar moet aanpassen om op alle plekken aan die wijziging te voldoen. Als ik nieuwe code schrijf of oude code refactor en er zitten geen opmerkingen of fouten in het project dan kan ik het compileren en 95% zeker zijn dat het gewoon werkt, zelfs zonder te testen. (Even los van logische fouten zoals x+4 waar ik x+3 had bedoeld natuurlijk.)

Het enige dat me voor mijn project nog te doen staat om het "perfect" te maken is het toevoegen van een set100% dekkende tests waarmee alle functie worden getest. Dan kan ik er nog veel meer gegarandeerd van zijn dat er niks stuk gaat als ik code aanpas of toevoeg.

Gelukkig is dit een hobby-project waar geen deadlines aan zitten (behalve de enige echte deadline: als ik zelf zou overlijden :+) en waar ik zo lang over kan doen als ik wil. Het is tevens een project dat eigenlijk nooit af gaat zijn, dus ik heb tijd zat.

[Reactie gewijzigd door Katsunami op 22 juli 2024 15:25]

Gezien de zero-cost abstractions lijkt het me onwaarschijnlijk dat iterators trager zouden zijn dan 'de ouderwetse manier'? Daarnaast zijn ze ergonomisch/idiomatic in gebruik, ik zou niet lang twijfelen om ze te gebruiken.

Hier effe opgezocht: https://doc.rust-lang.org/book/ch13-04-performance.html .

"The point is this: iterators, although a high-level abstraction, get compiled down to roughly the same code as if you’d written the lower-level code yourself. "
Voor jou lijkt het misschien onwaarschijnlijk, maar een praktijktest wijst uit dat in dit specifieke geval een iterator 10% trager is dan een simpele for-loop.

Deze "specifieke situatie" is in een schaakprogramma dat ergens rond de 6-7 miljoen zetten / seconde beoordeelt (op een i7-6700K, 1 kern), in een loop waarvoor ik de iterator zelf moet schrijven. Zover ik heb gezien heb ik de meest efficiënte manier gebruikt, maar ik kan niet aan een if-statement ontkomen, dat ik niet nodig heb als ik simpelweg een for-loop gebruik. Dat extra if-statement kost 10% snelheid. (Een stelling waarin het programma normaal 7 miljoen zetten/seconde beoordeelt valt terug naar ~6.3 miljoen zetten/seconde.)

Ook sommige andere dingen, zoals het "new type pattern" om types te isoleren (zodat je niet per ongeluk twee integers die verschilende dingen betekenen omwisselt in een functie-aanroep) kosten een fractie aan snelheid, die je gaat merken als code miljoenen keren per seconde wordt uitgevoerd.

Toegegeven, het is een heel specifiek programma. In "normale" programma's zou ik zonder aarzelen een iterator of een new type pattern gebruiken, omdat die normalerwijze

1 - niet zo specifiek afhankelijk zijn van brute snelheid
2 - snelheden als deze niet eens kunnen bereiken

Een normaal programma dat 10% trager is, is gewoon iets trager. Een schaakprogramma dat 10% trager is speelt zwakker dan een volledig gelijkwaardige, maar niet tragere versie.
Wat dacht je van Godot? Kan je programmeren in C# (alhoewel ik zelf liever GDScript gebruik).
Even voor wat duidelijkheid: er is geen "oude" Visual Studio. Er is nog steeds een Visual Studio 2022 die doorontwikkeld wordt. Visual Studio is een IDE, Visual Studio Code is een Editor met debugging tools. Grotere C# projecten zijn veel beter te debuggen in Visual Studio dan in Visual Studio Code.
Mwah, de originele VS heeft in mijn ogen al wel een tijdje stilgestaan. Er is onder de motorkap wat veranderd en het thema is een paar keer over de kop gegooid, maar de responsiveness en autosuggesties voelen eigenlijk niet heel verschillend tussen VS2012 en VS2021. De vernieuwingen zijn er een beetje uit lijkt het wel. Als Microsoft nieuwe features introduceert (denk aan Copilot om geheel automatisch intellectueel eigendom te stelen) dan lijkt de focus vooral te liggen op VS Code.

Visual Studio is een beetje ondergeschoven geraakt door het gratis aanbod. Logisch ook, want VS is snel duurder dan de Jetbrains suite en voor alles behalve C#/C++ Windows-specifiek werk heeft Jetbrains de macht van VS in mijn ogen een beetje verstoten. Met Rider heeft Jetbrains behoorlijke competitie opgezet in Microsoft's eigen achtertuin. Ik ken bijvoorbeeld ook niemand die VS nog gebruikt voor Python of Typescript. VS Code wel natuurlijk, die is tenslotte gratis en het is een prima IDE voor de meeste software.
Toevallig laatst Visual Studio gedownload,
Visual Studio is vooral aan te bevelen als je C# programeert, zelfs voor C/C++ zou ik iets anders proberen. Ik betwijfel of er zelfs Rust ondersteuning in zit, daarvoor kun je beter naar Visual Studio Code of Clion/intelliJ uitwijken.
Is Visual Studio en Visual Studio Code niet hetzelfde dan? Ik ga er vanavond even voor zitten :9
Visual Studio Code is Free and (almost) Open Source. Visual Studio heeft een gratis versie voor communities. Code kan met plug-ins voor allerlei talen gebruikt worden, maar is in essentie een tekst-editor. Visual Studio is Microsoft's one-stop-solution voor alles dat met ontwikkelen te maken heeft; schrijven, compilen, source control etc. Code heeft die functionaliteit wel, maar allemaal middels plugins.
Is niet hetzelfde.

Visual studio code is een light weight customizable code editor, free to use, je kan plugins gebruiken om van alles en nog wat te doen er mee. De meeste talen zijn ondersteund
https://code.visualstudio.com


Visual studio is een heavy duty code editor voor C++ en C# en misschien andere microsoft talen
https://visualstudio.microsoft.com

[Reactie gewijzigd door Moortu op 22 juli 2024 15:25]

Bedankt allemaal, super!

Zorg ik dat het goede programma en plugins klaar staan op zijn PC, voor makkelijke papa punten.
neen, die 2 zijn echt wel verschillend. Visual studio wordt vooral gebruikt om .NET te programmeren in zowel c# als visual basic. Visual studio code dient vooral om andere talen te programmeren. (Powershell, Python, Rust, ...)
Mja, RUST IDE's werken ook voor alle Jetbrains producten, is gewoon een plugin installeren, en maakt niet uit in welke IDE je op dat moment zit. Werkt bijzonder goed, en in combinatie met Netbeans werkt dit ook had ik gezien. Komt daarbij ook nog eens Github Copilot, waar snippets gepakt worden om sneller te programmeren, maakt het alleen nog maar beter :)
Compile-time garbage collection. Zo is het misschien te beschrijven.
Nee, je zou het kunnen zien als een C compiler waarbij de compiler je verbiedt om onveilige code te schrijven. Veilige code wordt dus gewoon op compile time afgedwongen.

Onder water genereert hij gewoon dezelfde machinecode als een C programma (min of meer).

[Reactie gewijzigd door Godson-2 op 22 juli 2024 15:25]

Let wel dat onveilige code nog steeds wordt geschreven: het unsafe-keyword bestaat met een goede reden. Diverse libraries zijn er in het verleden op gepakt dat ze fouten maakten in hun unsafe-code. Helaas zie jij als library-gebruiker weinig terug van die verborgen unsafe-ness. Helaas leidt het bestaan van unsafe bij sommige programmeurs tot overmoedigheid, omdat de meeste mensen nooit zelf unsafe code hoeven schrijven.

Dat wil niet zeggen dat de taal zijn beloftes niet nakomt, natuurlijk; je moet als programmeur nog steeds expliciet unsafe-blokken schrijven als je zelf de risico's wilt nemen. Grote beweringen als "de compiler verbiedt je om onveilige code te schrijven" moeten echter wel met een korrel zout genomen worden.
Een escape hatch zoals unsafe is nodig omdat je anders nooit kan concurreren met een taal als C.

Unsafe wordt voornamelijk gebruikt voor interop met C/C++ libraries of het besturingssysteem.

Als het goed is zit er bijna geen unsafe in je eigen programma's.

[Reactie gewijzigd door Godson-2 op 22 juli 2024 15:25]

Voor bepaalde concepten kan unsafe een uitkomst bieden zolang je zelf maar de nodige voorwaarden en het nodige gedrag valideert. Het maken van boomstructuren en dubbelgelinkte lijsten zijn bijvoorbeeld klassieke gevallen waar unsafe code correct kan en je leven een stuk makkelijker maakt zolang je maar oplet en de nodige validatie doet. Het kan natuurlijk ook zonder unsafe (RefCells en vrienden bijvoorbeeld) maar vaak gaat dat omslachtig, en nog met overhead ook!

Inderdaad, er zit bijna nooit unsafe code in je programma, maar de compiler laat je prima segmentatiefouten en buffer overflows introduceren als je daarom vraagt.
Mwoah, niet echt. Dat dacht ik ook, maar werd netjes gecorrigeerd hier:
https://gathering.tweaker...message/68498082#68498082

Deterministic garbage collection is een betere term.
Niet echt, tijdens compileren wordt je code wel geanalyseerd of je je variabelen correct gebruikt, maar er is geen garbage collection.

Om het eenvoudig uit te leggen: als een method A tijdens runtime zijn einde bereikt (de sluitende curly brace, de “scope”), worden variabelen gemaakt in method A (bijv let foo = “bar”) direct automatisch uit het geheugen verwijdert. De compiler checkt bijv of je een variabel niet probeert te gebruiken nadat deze al verwijdert is.

[Reactie gewijzigd door Bas.Bas.Bas op 22 juli 2024 15:25]

Interessante bijdrage. Zowel de achtergrond als hands-on.

Overigens denk ik dat het stuk over garbage collection beter had gekund, want het is natuurlijk niet zo dat garbage collection de enige manier is om null pointer objecten uit het geheugen te halen: er zijn genoeg talen die reference counting doen (C++, Swift, Python), garbage collection is met name toch een Java ding (nou ja en C# maar dat is historisch gezien gewoon de Microsoft versie van Java volgens o.a. Bob Martin), betere term is "memory management", zowel garbage collection als reference counting zijn immers automatische memory management technieken.

Hoare werkt ook aan Swift (kort door de bocht: de moderne iOS taal), niet voor niets dat zowel voor Rust als Swift bijvoorbeeld dus een "playground" beschikbaar is.
En memory management is ook te kort door de bocht. Elke taal met een met een heap doet aan memory management, dus ook C.

Overigens is reference counting is ook maar een lapmiddel (cyclische referenties...). Dus om dat onder dezelfde categorie als een (generatieve) garbage collector te plaatsen vind ik raar.

Maw. het artikel kan altijd uitgebreide maar is nooit volledig. Misschien is het dus zo wel goed genoeg. :)
Reference counting beschrijft ook niet helemaal wat er gebeurd.

In Rust zijn jouw objecten eigendom van een bepaalde scope. In Rust kun je referenties naar objecten doorgeven met functies, die hebben een lifetime. Als jij een referentie naar een object probeert te bewaren op een plaats die langer bestaat dan de scope waar het object eigendom van is, dan zal de compiler klagen dat je object niet lang genoeg leeft.

Als je reference counting wil toepassen in Rust heb je daar de RC of ARC voor. Handig voor bijvoorbeeld het delen van referenties tussen threads. Dan kan je object meerdere owners hebben. WIl je een muteerbaar object tussen threads delen, dan heb je bijvoorbeeld een Arc<Mutex<_ObjectType_>>. De Mutex is dan immutable kan dan in eigendom zijn van verschillende scopes, maar je object is eigendom van de Mutex en er kan dan maar 1 taak tegelijk toegang hebben tot je object.
.oisyn Moderator Devschuur® @royb313 april 2022 14:02
In Rust zijn jouw objecten eigendom van een bepaalde scope
Rust is hierin ook niet anders dan C++. Ook het in het artikel aangehaalde concept RAII komt uit C++.

Wat Rust in de taal echter afdwingt is dat de ownership van een object altijd slechts op 1 plek ligt, op zo'n manier dat je er ook niet meer bij kan als je de ownership niet hebt; het doorgeven van een referentie naar een object aan iemand anders impliceert dat jij die referentie dan ook niet meer hebt. Heel kort door de bocht een beetje vergelijkbaar met std::unique_ptr uit C++, ware het niet dat die laatste wel toestaat om de ruwe pointer op te vragen en die rond te kopiëren (wat in Rust overigens ook nog steeds kan, maar louter in unsafe blokken).

(Dit even ter aanvulling voor de lezer, niet zozeer gericht op jou ;))

[Reactie gewijzigd door .oisyn op 22 juli 2024 15:25]

Het probleem met C++ is dat niets wordt afgedwongen.

Veel C++ frameworks gebruiken RAII en zijn daardoor vaak heel veilig, maar niets weerhoudt je om gewoon straight C pointers te manipuleren en void casts te doen. Zo kan je dus alsnog in de problemen komen.

[Reactie gewijzigd door Godson-2 op 22 juli 2024 15:25]

.oisyn Moderator Devschuur® @Godson-213 april 2022 16:53
Inderdaad, met C++ kun je heel veilige code schrijven, maar de nadruk ligt hier op "kan". Hoewel het houden aan moderne C++ technieken je hier heel erg bij helpt, werkt men in de praktijk toch vaak met oude codebases waarin pointers rondgestrooid worden alsof het een lieve lust in.

Ik zie het in mijn werkgebied ook. Ik zit al 18 jaar in de gamesindustrie, waar met name C++ wordt geschreven. Het is erg lastig om de codebases te moderniseren, met als gevolg dat iedereen maar op de oude voet door blijft gaan. In mijn eigen hobbyprojecten heb ik daarentegen nooit last van dit soort issues.

Maar goed, wat ik eerder al zei, binnenkort dus fulltime Rust programmeren. Ben benieuwd :P
Ik dacht dat je een grapje maakte.
.oisyn Moderator Devschuur® @Godson-213 april 2022 17:03
Ja dat dacht ik al, maar er is geen woord van gelogen ;). Rust wordt, ook binnen de gamesindustrie, wel op een aantal plekken gebruikt. Embark Studios in Zweden (met veel ex-werknemers van DICE) programmeert bijvoorbeeld vrijwel volledig in Rust. Ik ga aan de slag bij een klein Nederlands bedrijfje dat weer met hen samenwerkt.
Het probleem voor mij is dat omdat Rust geen UI frameworks heeft dat je er weinig in kan maken behalve command line tooltjes of zo.

Misschien moet ik maar een game maken met dat Good Game Easily framework of zo.
.oisyn Moderator Devschuur® @Godson-213 april 2022 17:20
Ik vind dat framework ook wel interessant klinken, heb me nog niet zo verdiept in wat er allemaal beschikbaar is. Ik moet zeggen dat ik als echte C++ fanaat het ook niet zo snel zie gebeuren dat ik voor de hobbysfeer overstap op Rust. C++ heeft dan wel bagage, maar dat wil niet zeggen dat er niet nog steeds veel nieuwe ontwikkelingen zijn in de taal zelf.
Zeker, wij gebruiken veel C++ maar denk dat Rust toch wel de toekomst zou kunnen worden juist ook voor Embedded en IoT. C++ evolueert ook wel maar je kunt het nog op de oude manier doen en dat is misschien wel geen goed idee.
Er zijn ook manieren om GC te mijden door objecten hergebruiken ipv aan te maken en vrij te geven. Gezien allocatie en de-allocatie duur is kwa cpu cycles.
Existance based programming. Kan met memory management en GC.
Een object heeft dan ID key of Handle.
Gaat goed samen met Functional en data oriented programming.
Je alloceerd in bulk.
Je zorgt ook dat memory fragmentatie niet uit de hand loopt.

Je programma zal met die object pools meer memory gebruiken van inactieve data structures of objecten. Maar heden is memory fragmentatie mogelijk meer isue dan te weinig heap memory. Daar zal ook balans in gevonden worden
Naast random acces en pool array van objecten en dus ook optimaliseren voor data locality.
Voor games is niet zo bijzonder voor bijvoorbeeld een RTS game zoals Annilation om max limiet aan units te hebben. Van 200. In heden met 8GB en 32GB is 1000 a 10000 vaker al geen probleem. Voor moderne games is 1000 geen probleem. En 10000 is te veel voor een micro management gameplay type RTS
Voor de mensen die liever op het IntelliJ platform werken is er ook een plugin beschikbaar:

https://intellij-rust.github.io/

Op dit item kan niet meer gereageerd worden.