monien kehittäjien tavoin olen ollut kiinnostunut Rustista jo jonkin aikaa. Ei vain siksi, että se näkyy niin paljon otsikoita Hacker News, tai koska uusi lähestymistapa kieli vie turvallisuutta ja suorituskykyä, mutta myös siksi, että ihmiset näyttävät puhua siitä erityistä tunnetta rakkautta ja ihailua. Kaiken lisäksi Rust kiinnostaa minua erityisesti siksi, että sillä on samat tavoitteet ja ominaisuudet kuin lempikielelläni: Swift. Koska olen viime aikoina ottanut aikaa kokeilla ruostetta joissakin pienissä henkilökohtaisissa projekteissa, halusin ottaa vähän aikaa dokumentoida vaikutelmiani kielestä, erityisesti siitä, miten se vertaa Swiftiin.

isossa kuvassa

Rustilla ja Swiftillä on paljon yhteistä: molemmat ovat koottuja kieliä, joissa on tehokkaat, modernit tyyppijärjestelmät ja turvallisuuspainotus. Ominaisuudet, kuten algebrallinen tyypit, ja ensiluokkainen käsittely valinnaisia arvoja auttaa siirtämään monia luokkia virheitä runtime kääntää aikaa molemmilla näillä kielillä.

miten nämä kielet sitten eroavat toisistaan? Paras tapa luonnehtia eroa on:

Swiftin avulla on helppo kirjoittaa turvallista koodia.
ruoste vaikeuttaa vaarallisen koodin kirjoittamista.

nämä kaksi väitettä saattavat kuulostaa samanlaisilta, mutta niissä on tärkeä ero. Molemmilla kielillä on Työkalut turvallisuuden saavuttamiseksi, mutta ne tekevät erilaisia kompromisseja sen saavuttamiseksi: Swift priorisoi ergonomian suorituskyvyn kustannuksella, kun taas Rust priorisoi suorituskyvyn ergonomian kustannuksella.

vaihtokauppa: Suorituskyky vs ergonomia

suurin ero tärkeysjärjestyksessä näkyy siinä, miten nämä kielet suhtautuvat muistinhallintaan. Aloitan ruosteesta, koska kielen lähestymistapa muistinhallintaan on yksi sen ainutlaatuisista myyntivalteista.

ruosteessa muistia hallitaan ensisijaisesti staattisesti (kyllä on muitakin muistinhallintamuotoja kuten referenssilaskenta, mutta jätetään ne toistaiseksi huomiotta). Tämä tarkoittaa sitä, että Rust-kääntäjä analysoi ohjelmasi ja päättää sääntöjen mukaan, milloin muisti jaetaan ja vapautetaan.

Turvallisuuden takaamiseksi Rust käyttää uudenlaista strategiaa nimeltä borrow checking. Käytännössä tämä toimii siten, että ohjelmoijana joka kerta, kun ohitat muuttujan (eli viittauksen muistin sijaintiin), sinun täytyy määrittää, onko viittaus mutable vai muuttumaton. Kääntäjä käyttää sitten sääntöjä varmistaakseen, että et voi mutatoida yhtä muistikappaletta kahdessa paikassa yhtä aikaa, jolloin on todistettavissa, että ohjelmassasi ei ole datakilpailuja.

tällä lähestymistavalla on joitakin erittäin hyödyllisiä ominaisuuksia muistin käytön ja suorituskyvyn kannalta. Lainatarkistus voi olla hyvin parsimoninen muistin kanssa, koska se yleensä välttää arvojen kopioimista. Sillä vältetään myös roskankeräyksen kaltaisen ratkaisun suorituskyky, koska työ tehdään käännösaikaan eikä suoritusaikaan.

siinä on kuitenkin joitain haittoja helppokäyttöisyyden suhteen. Ruosteessa omistamisen luonteesta johtuen on olemassa joitakin suunnittelukuvioita, jotka eivät yksinkertaisesti toimi ruosteessa. Esimerkiksi, se ei ole vähäpätöinen toteuttaa jotain kaksinkertaisesti linkitetty lista tai globaali muuttuja. Tämä todennäköisesti muuttuu intuitiivisemmaksi ajan myötä, ja näihin kysymyksiin löytyy kiertoteitä, mutta Rust varmasti asettaa ohjelmoijalle rajoituksia, joita ei ole muilla kielillä.

vaikka siitä ei niin usein puhuta kuin ruosteesta, Swiftillä on myös mielenkiintoinen tarina muistinhallinnan suhteen.

Swiftillä on kaksi perustyyppiä muuttujia: viitetyypit ja arvotyypit. Yleensä vertailutyypit jaetaan kasaan, ja niitä hallitaan referenssilaskennalla. Tämä tarkoittaa sitä, että suorituksen aikana seurataan referenssilasketun kohteen viittausten määrää, ja objekti poistetaan, kun luku saavuttaa nollan. Referenssilaskenta Swiftissä on aina atomista: tämä tarkoittaa, että aina kun referenssilaskenta muuttuu, kaikkien suorittimen kierteiden välillä on oltava synkronointi. Tämän etuna on se, että se poistaa mahdollisuuden, että viittaus vahingossa vapautetaan monisäikeisessä sovelluksessa, mutta sillä on merkittävä suorituskykykustannus, koska suorittimen synkronointi on erittäin kallista.

Rustilla on myös työkaluja referenssilaskentaan ja atomivertailulaskentaan, mutta nämä ovat opt-in-järjestelmiä sen sijaan, että ne olisivat oletusarvo.

arvotyypit sen sijaan ovat yleisesti pinoja ja niiden muistia hallitaan staattisesti. Arvolajien käyttäytyminen Swiftissä on kuitenkin paljon erilaista kuin se, miten Rust käsittelee muistia. Swiftissä arvotyypeillä on niin sanottu” copy-on-write ” – käyttäytyminen kopioidaan oletusarvoisesti, mikä tarkoittaa, että aina kun arvotyyppi kirjoitetaan uuteen muuttujaan tai siirretään funktiolle, tehdään kopio.

Copy-on-write-kopioinnilla oletusarvoisesti saavutetaan joitakin samoja lainatarkistuksen tavoitteita: ohjelmoijana sinun ei yleensä koskaan tarvitse pelätä arvon muuttuvan mystisesti jonkin odottamattoman sivuvaikutuksen takia muualla ohjelmassa. Se vaatii myös hieman vähemmän kognitiivista kuormitusta kuin lainatarkistus, sillä ruosteessa on kokonaisia omistukseen liittyviä kääntöaikavirheitä, joita Swiftissä ei yksinkertaisesti ole. Sillä on kuitenkin hintansa: lisäkopiot vaativat lisämuistin käytön ja SUORITINSYKLIEN suorittamisen.

ruosteessa on myös mahdollista kopioida arvoja lainausvirheiden hiljentämiseksi, mutta tämä lisää visuaalista kohinaa, koska kopiot on erikseen määriteltävä.

tässä on siis hyvä esimerkki näiden kahden kielen tekemistä kompromisseista: Swift antaa laajoja oletuksia siitä, miten muistia tulisi hallita säilyttäen kuitenkin turvallisuustaso. Se on vähän kuin miten C++ ohjelmoija voisi käsitellä muistia parhaiden käytäntöjen mukaisesti ennen kuin antaa paljon ajatellut optimointia. Tämä tekee siitä erittäin helppoa hypätä ja kirjoittaa koodia antamatta paljon huomiota matalan tason yksityiskohtia, ja myös saavuttaa joitakin perus run-time turvallisuus ja oikeellisuus takeita et saa kielellä kuten Python tai jopa Golang. Kuitenkin se tulee joitakin suorituskyvyn kallioita, joka on helppo pudota ilman edes tajuamatta sitä, kunnes suoritat ohjelman. On mahdollista kirjoittaa korkean suorituskyvyn Swift-koodia, mutta tämän saavuttaminen vaatii usein huolellista profilointia ja optimointia.

Rust taas antaa paljon erikoistyökaluja, joilla voi määritellä, miten muistia tulee hallita, ja asettaa sitten kovia rajoituksia sille, miten niitä käyttää välttääkseen vaarallista käytöstä. Tämä antaa sinulle erittäin mukava suorituskyky ominaisuudet heti kättelyssä, mutta se ei vaadi sinua ottamaan ylimääräisiä kognitiivisia overhead varmistaa, että kaikki säännöt noudatetaan.

olen ymmärtänyt, että vaikka näillä kielillä on joitakin yhteisiä tavoitteita, niillä on pohjimmiltaan erilaisia ominaisuuksia, jotka soveltuvat erilaisiin käyttötapauksiin. Rust, esimerkiksi, tuntuu selkeä valinta jotain sulautetun kehityksen, jossa optimaalinen käyttö muistin ja CPU syklit on erittäin tärkeää, ja jossa koodi-kääntää-run silmukka voi olla hitaampi, joten se on arvokasta kiinni jokaisen mahdollisen ongelman käännösaikaan. Kun taas Swift voisi olla parempi valinta jotain data science, tai serverless logiikka, jossa suorituskyky on toissijainen huolenaihe, ja se on arvokasta työskennellä lähempänä ongelma verkkotunnuksen ilman harkita paljon matalan tason yksityiskohtia.

olen joka tapauksessa erittäin kiinnostunut seuraamaan näitä molempia kieliä tulevaisuudessa, ja seuraan tätä postausta tekemällä lisää havaintoja Swiftin ja Rustin vertailusta.

Vastaa

Sähköpostiosoitettasi ei julkaista.