1 Tavoitteet. 2 Periaatteet ja ominaisuudet. 2.1 Tyyppipäättely

Samankaltaiset tiedostot
Concurrency - Rinnakkaisuus. Group: 9 Joni Laine Juho Vähätalo

ELM GROUP 04. Teemu Laakso Henrik Talarmo

15. Ohjelmoinnin tekniikkaa 15.1

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

D-OHJELMOINTIKIELI. AA-kerho, 33. Antti Uusimäki. Arto Savolainen

Koka. Ryhmä 11. Juuso Tapaninen, Akseli Karvinen. 1. Taustoja 2. Kielen filosofia ja paradigmat 3. Kielen syntaksia ja vertailua JavaScriptiin Lähteet

15. Ohjelmoinnin tekniikkaa 15.1

Osoitin ja viittaus C++:ssa

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

Haskell ohjelmointikielen tyyppijärjestelmä

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia

Ohjelmoinnin peruskurssien laaja oppimäärä

lausekkeiden tapauksessa. Jotkin ohjelmointikielet on määritelty sellaisiksi,

Groovy. Niko Jäntti Jesper Haapalinna Group 31

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

11/20: Konepelti auki

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

TIE Principles of Programming Languages CEYLON

Ohjelmoinnin peruskurssien laaja oppimäärä

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

4. Luokan testaus ja käyttö olion kautta 4.1

Ruby. Tampere University of Technology Department of Pervasive Computing TIE Principles of Programming Languages

Rajapinnat ja olioiden välittäminen

Ohjelmoinnin peruskurssien laaja oppimäärä

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

815338A Ohjelmointikielten periaatteet

Clojure, funktionaalinen Lisp murre

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

812341A Olio-ohjelmointi, I Johdanto

TIE Principles of Programming Languages. Seminaariesityksen essee. Ryhmä 18: Heidi Vulli, Joni Heikkilä

Solidity älysopimus ohjelmointi. Sopimus suuntautunut ohjelmointi

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

C++11 lambdat: [](){} Matti Rintala

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Objective-C. Ryhmä 35: Ilpo Kärki Aleksi Pälä

1. Johdanto. 2. Ominaisuudet Tietotyypit ja tyypitys

Tietorakenteet ja algoritmit

PERL. TIE Principles of Programming Languages. Ryhmä 4: Joonas Lång & Jasmin Laitamäki

Groovy. Samuli Haverinen, Aki Hänninen. 19. marraskuuta 2015

Ohjelmoinnin peruskurssien laaja oppimäärä

Laajennetaan vielä Ydin-Haskellia ymmärtämään vakiomäärittelyt. Määrittely on muotoa

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006

Common Lisp Object System

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmointi 2. Jussi Pohjolainen. TAMK» Tieto- ja viestintäteknologia , Jussi Pohjolainen TAMPEREEN AMMATTIKORKEAKOULU

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. II Johdanto olio-ohjelmointiin

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Kooste. Esim. Ympyrän keskipiste voidaan ajatella ympyrän osaksi.

Dart. Ryhmä 38. Ville Tahvanainen. Juha Häkli

Geneeriset luokat. C++ - perusteet Java-osaajille luento 6/7: Template, tyyppi-informaatio, nimiavaruudet. Geneerisen luokan käyttö.

Ohjelmoinnin peruskurssien laaja oppimäärä

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

.NET ajoympäristö. Juha Järvensivu 2007

12. Monimuotoisuus 12.1

Oliot ja tyypit. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos

14.1 Rekursio tyypitetyssä lambda-kielessä

Ydin-Haskell Tiivismoniste

C++11 Syntaksi. Jari-Pekka Voutilainen Jari-Pekka Voutilainen: C++11 Syntaksi

Sisällys. 7. Oliot ja viitteet. Olion luominen. Olio Java-kielessä

Harjoitustyö: virtuaalikone

Sisällys. 11. Rajapinnat. Johdanto. Johdanto

Ohjelmoinnin peruskurssien laaja oppimäärä, kevät

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

TIES542 kevät 2009 Tyyppiteorian alkeet

TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 27. lokakuuta 2009

- Komposiittityypit - Object (Mukaanlukien funktiot) - Array. - Erikoisdatatyypit - null - undefined

Qt perusteet. Juha-Matti Vanhatupa. (vanhan kurssin Graafisen käyttöliittymän ohjelmointi materiaalia)

Ohjelmoinnin peruskurssien laaja oppimäärä

Muutamia peruskäsitteitä

12. Monimuotoisuus 12.1

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 30. marraskuuta 2015

Kääntäjän virheilmoituksia

7. Oliot ja viitteet 7.1

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEA255 Tietotekniikan teemaseminaari ohjelmointikielet ja kehitysalustat. Antti-Juhani Kaijanaho. 16. helmikuuta 2011

Dynaaminen muisti. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät 2017.

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

Uusi näkökulma. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIE Ohjelmistojen suunnittelu

Luku 3. Listankäsittelyä. 3.1 Listat

Prolog kielenä Periaatteet Yhteenveto. Prolog. Toni ja Laura Fadjukoff. 9. joulukuuta 2010

Ohjelmoinnin peruskurssien laaja oppimäärä

sama tyyppi (joka vastaa kaikkien mahdollisten arvojen summa-aluetta). Esimerkiksi

815338A Ohjelmointikielten periaatteet

Ohjelmoinnin peruskurssien laaja oppimäärä

Esimerkkiprojekti. Mallivastauksen löydät Wroxin www-sivuilta. Kenttä Tyyppi Max.pituus Rajoitukset/Kommentit

Ohjelmoinnin peruskurssien laaja oppimäärä

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. IX Suunnittelumallit Proxy, Factory Method, Prototype ja Singleton

12 Mallit (Templates)

Java-kielen perusteet

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

Sulautettujen järjestelmien skaala on niin laaja, että on erittäin vaikea antaa yleispätevää kuvausta siitä millainen on sulautettu järjestelmä.

Loppukurssin järjestelyt C:n edistyneet piirteet

4. Lausekielinen ohjelmointi 4.1

Transkriptio:

1 Tavoitteet Rustin ensimmäinen tavoite on olla vakavasti otettava vaihtoehto C:lle ja C++:lle kaikissa sovelluksissa. Hyvän suorituskyvyn lisäksi tämä tarkoittaa deterministisyyttä, minimaalista ajoympäristöä ( runtime ) ja pääsyä matalan tason ominaisuuksiin. Rustin suoritusmalli on käytännössä sama kuin C:n sisältäen lineaarisen muistiavaruuden, pinon, säikeet ja niin edelleen ja näin ollen käännetyt Rust-ohjelmat muistuttavat suuresti käännettyjä C(++)-ohjelmia. Rustin toinen tavoite on käyttää muistia turvallisesti ilman roskien keruuta. Tässä suhteessa se eroaa suuresti C:stä ja C++:sta, joiden turvallisuudesta vastaa lähinnä (heikohko) staattinen tyypitys. Muistiturvallisuus pyritään Rustissa lähtökohtaisesti ulottamaan myös rinnakkaisuuteen. Kolmanneksi Rust pyrkii tarjoamaan tuottavuutta lisääviä abstraktioita. C++:n tavoin Rust pyrkii siihen, että abstraktiot olisivat mahdollisimman halpoja mieluiten ilmaisia. Uudempana kielenä Rust tarjoaa tietenkin paremman ja vähemmän ongelmaisen tai ainakin modernimman ja yksinkertaisemman abstraktiojoukon joka on selkeästi saanut vaikutteita funktionaalisista kielistä, erityisesti ML-perheestä 1. Keveys Turvallisuus Abstraktiot 2 Periaatteet ja ominaisuudet Pohjimmiltaan Rust on siis matalan tason käännettävä imperatiivinen kieli. Se sisältää myös olio- ja funktionaalisen ohjelmoinnin keskeisiä ominaisuuksia. Se on siis useimpien yleiskäyttöisten ohjelmointikielten tapaan moniparadigmainen 2. Koska Rustin suoritusmalli ja kohdeyleisö ovat pitkälti yhtenevät C(++):n kanssa, myös sen syntaksista on tehty samankaltainen 3. 2.1 Tyyppipäättely Rustissa on vahva staattinen tyypitys. Tyyppien käyttöä helpottaa kuitenkin se että Rust osaa päätellä (paikallisten) muuttujien tyypit kontekstista. 1 ML-perheen tunnetuimmat jäsenet ovat Standard ML, OCaml ja Haskell. 2 Fanaattisimpia yhden paradigman yleiskäyttöisiä kieliä lienevät Java ja Haskell. 3 Tietenkin C:n ja C++:n valitettavista kontekstiriippuvuuksista on hankkiuduttu eroon. 1

2.2 Siirtosemantiikka ja omistajuusmalli Rustissa kaikella datalla on yksikäsitteinen omistaja. Omistaja on muuttuja, tietueen kenttä tms., joka käytännössä määrää datan elinajan. Omistajuutta ei siis voi jakaa, mutta sen voi kyllä siirtää ja oletuksena näin tapahtuukin kun data sijoitetaan muuttujaan tai tietueen kenttään, annetaan parametrina funktiolle ja niin edelleen. Rust käyttää siis pääasiallisesti kopio- tai viitesemantiikan sijaan siirtosemantiikkaa. Rustissa on myös viitteet, joiden käyttöä kutsutaan omistajuusmetaforan jatkeena lainaamiseksi ( borrowing ). Lainaukselle on tiukat säännöt: Viite ei voi elää pidempään kuin datan omistaja. Dataan saa olla joko mielivaltainen määrä lukuviitteitä (&) tai yksi ainoa kirjoitusviite (&mut). Myös omistaja katsotaan siinä mielessä viitteeksi, että lukuviitteiden olemassa ollessa omistajankaan kautta dataa ei voi kirjoittaa ja kirjoitusviitteen olemassa ollessa dataan ei pääse omistajankaan kautta käsiksi laisinkaan. Nämä säännöt muistuttavat pitkälti rinnakkaisuudesta tuttua ReaderWriter-lukkoa. Omistajuusmalli kytkeytyy vahvasti Rustin tavoitteeseen olla muistiturvallinen ilman roskienkeruuta. Se estää esimerkiksi vapautettuun muistiin viittaamisen. Omistajuusmalli on myös keskeisessä osassa Rustin tavoitellessa säieturvallisuutta. Tyypille voi myös luoda eksplisiittisen kopiorakentajan eli.clone()-metodin toteuttamalla piirteen Clone. Mikäli clone on puhdas muistikopio (kuten C:ssä), tämän voi kertoa kääntäjälle toteuttamalla piirteen Copy. Tällöin tyyppi alkaa käyttämään siirtosemantiikan sijaan kopiosemantiikkaa, jolloin clone:a ei enää tarvitse kutsua ja kääntäjä voi optimoida kopioinnit paremmin. Näin tekevät esimerkiksi kaikki primitiiviset numeeriset tyypit. 2.3 Metodit ja polymorfisuus Funktioiden lisäksi Rustissa on mahdollista määritellä staattisia ja dynaamisia metodeja, joiden kutsusyntaksit ovat tutut :: ja.. ML-sukuisten kielten tapaan Rustissa on myös parametrinen polymorfisuus eli tuttavallisemmin geneeriset tyypit tai tyyppimuuttujat. Rustissa ne muistuttavat toiminnaltaan ja syntaksiltaan C++:n malleja (template) 4 eli metodit voidaan valita käännösaikaisten tyyppien perusteella. Ad hoc -polymorfisuus on Rustissa määritelty piirteiden (trait) avulla. Piirteet vastaavat suunnilleen Haskellin tyyppiluokkia ( type classes ) eli ne ovat tyypeille suunnilleen sitä mitä tyypit ovat arvoille. Haskellin tapaan piirteitä voi myös käyttää tyyppimuuttujien rajoittamiseen. C++:n malleihin verrattuna tässä on se etu, että piirteiden käyttö voidaan tarkistaa monomorfisoimatta koodia ensin, mikä sekä parantaa virheilmoituksia että lyhentää käännösaikaa. Piirteitä voidaan käyttää myös olio-ohjelmoinnista tuttuun dynaamiseen metodinvalintaan Javan rajapintojen (interface) tapaan. Piirteen toteuttavan tyypin alkiosta on mahdollista tehdä ns. piirreolio ( trait object ), jolle on määritelty ainoastaan piirteen sisältämät operaatiot. 4 Sillä erotuksella että Rustissa nämä ovat aidosti vain osa tyyppijärjestelmää eivätkä jokin yleinen metaohjelmointimekanismi. 2

Yleistä tyyppien välistä perintämekanismia Rustissa ei ole ollenkaan; nykyäänhän Javassakin rajapintoja pidetään suositeltavampana ratkaisuna. Piirteet voivat kyllä periä toisiltaan mutta tämä toimii kuten Haskellissa eli vain saa kääntäjän pakottamaan perivän piirteen toteuttajat toteuttamaan perivän piirteen lisäksi myös perityn piirteen. 2.4 Hahmontunnistus ja enum Hahmontunnistus ( pattern matching ) on monista funktionaalisista kielistä tuttu ominaisuus. Rustissa on useampia kohtia joissa hahmoja ( pattern ) voi käyttää, muun muassa sitoessa dataa muuttujiin ja match-lausekkeessa. Match vastaa ML:n samannimistä rakennetta (Haskellissa case) ja on yleisempi versio C-sukuisten kielten switch-rakenteesta. Rustin enum-tyypit vastaavat ML-sukuisten kielten nimettyjä unioneja ( tagged union ) ja korvaavat sekä C:n enum:it että union:it ollen samalla turvallisempia. Tämä turvallisuus on pitkälti hahmontunnistuksen ja siihen liittyvien tarkistusten ansiota. Rustissa myös virheenkäsittely tehdään yleensä Result- ja Option-nimisten enum:ien avulla poikkeusten sijaan 5. 2.5 Makrot Rustissa metaohjelmointi tapahtuu hygieenisilla makroilla, jotka toimivat lekseemivirran sijaan jäsennyspuun ( parse tree ) tasolla. Makrojärjestelmä ei muistuta siis niinkään C- makroja tai C++-malleja vaan pikemminkin Schemen makrojärjestelmää. Tällä hetkellä ainoa siunattu makromekanismi on macro_rules!, joka vastaa Schemen syntax-rules:ia. Makrokutsut sisältävät aina huutomerkin (esim. println!( {}, foo)), jotta ne erottuisivat funktiokutsuista ja kielen omista rakenteista. 2.6 unsafe Joskus on tehtävä sellaisia operaatioita, joita kääntäjä ei voi todistaa turvallisiksi. Näitä ovat esim. globaalien muuttujien asettamien, raa oista osoittimista (*const _ ja *mut _) lukeminen, C-funktoiden kutsuminen sekä mielivaltaiset tyyppimuunnokset. Tätä varten Rustissa on unsafe-avainsana, jolla kääntäjän saa sallimaan nämä operaatiot ja siirtämään niiltä osin vastuun turvallisuudesta ohjelmoijan harteille. Unsafe-mekanismi on erittäin karkea, mutta ainakin avainsanan käyttö osoittaa selvästi vaarallisimmat kohdat. 3 Erityispiirteet 3.1 Siirtosemantiikka Kopio- tai viitesemantiikkaan tottuneelle (eli käytännössä kaikille) siirtosemantiikka aiheuttaa hankaluuksia. Sijoitukset ja jopa sellaisten funktioiden kutsut, joiden argumentteja ei ole määritelty viitteiksi siirtävät datan, minkä jälkeen edellisen omistajan käyttö onkin kiellettyä! Imperatiivinen ohjelmointi vaatiikin Rustissa viitteiden ahkeraa käyttöä 6. 5 Itse asiassa kielessä ei edes ole poikkeuksia, ne kun harvemmin johtavat täysin luotettavaan koodiin. 6.clone():n runsas käyttö on yleensä aloittelijan merkki. 3

3.2 Resource Acquisition Is Initialization C++:n tapaan Rustissa on mahdollista määritellä tyypeille deterministisiä purkajia. Tämä mahdollistaa nk. RAII-idiomin (ks. otsikko) käytön eli erinäisten resurssien kuten muistin ja tiedostojen elinkaaren sitomisen jonkin tyypin alkion elinkaareen niin että resurssi otetaan käyttöön rakentajassa ja vapautetaan purkajassa 7. 3.3 Minimaalinen ajoympäristö Rustin pienen ajoympäristön ansiosta se soveltuu myös mm. Python-tulkin laajennusten ja ajurien kirjoittamiseen. On mahdollista myös käyttää täyden standardikirjaston (std) sijaan todella minimaalista ajoympäristöä (core). Tällöin Rustilla on mahdollista toteuttaa myös sulautettuja järjestelmiä ja käyttöjärjestelmiä (esim. Redox). 4 Kokemuksia ja vertailua C-kielessä ei ole kovinkaan suurta pyrkimystä turvallisuuteen ja sen abstraktiojoukko on (tarkoituksella) erittäin pieni ja yksinkertainen. Niinpä C++ on Rustille yleensä se mielekkäin vertailukohde. 4.1 Koodin ja käännöksen organisointi Kuten useimpien kielten paitsi C(++):n, Rustin moduulijärjestelmä ei perustu koodin leikkaamiseen ja liimaamiseen. Myöskään erillisiä otsikkotiedostoja ei tarvitse ylläpitää eikä (Cargo-työkalun ansiosta) makefilejä tai vastaavia kirjoittaa. 4.2 Turvallisuus Tyypityksen puolesta Rustin käyttö on lähempänä ML-sukuisia kieliä kuin C++:aa. Tyypitys on paljon vahvempi kuin C++:ssa ja toisaalta muuttujien tyyppejä tarvitsee tyyppipäättelyn ansiosta kirjoittaa melko vähän. Normaalien tyyppivirheiden lisäksi Rustkääntäjä on hyvin tarkka siitä, että omistajuusmallia noudatetaan ja erityisesti aloittelevaa Rust-ohjelmoijaa kääntäjä patistaa tämän tästä korjaamaan tähän liittyviä ongelmia. Ennen pitkää kääntäjän kanssa tappeleminen muuttuu luottamukseksi sitä kohtaan. Tyyppijärjestelmän tiukkapipoisuuden lisäksi Rust-ohjelmoijan turvallisuudentunnetta lisää se, että monet asiat tehdään oletuksena turvallisella tavalla. Esimerkiksi alustamattomien muuttujien ja kenttien luominen tai väärän tyypin lukeminen enum:eista on mahdotonta ilman unsafe:a. 4.3 Polymorfisuus ja geneerisyys Rustissa geneeristen funktioiden, tietueiden ja piirteiden määrittely ja käyttö vaatii vähemmän kirjoitustyötä kuin C++:ssa tyyppipäättelyn sekä määrittelyn kevyemmän syntaksin ansiosta. Parametrinen polymorfisuus tyyppijärjestelmän osana myös tuntuu selkeämmältä kuin C++:n yleiskäyttöinen mallimekanismi. Piirteet estävät tarpeettoman monimutkaisten ja vaikeasti ylläpidettävien luokkahierarkioiden askartelun. Niiden käyttö geneeristen tyyppien yhteydessä parantaa virheilmoituksia ja jossain määrin myös tyyppiturvallisuutta. 7 Rustissa tosin rakentajat ovat vain staattisia jäsenfunktioita ja purkaja määritettään toteuttamalla piirre Drop. 4

4.4 Elinkaarioperaatiot C++:ssa elinkaarioperaatiot eli rakentajat, kopiorakentajat ja purkajat ovat selkeä kokonaisuus. Rustissa elinkaarikokonaisuus on hajotettu staattisiin metodeihin (rakentaja) ja erinäisiin piirteisiin (Clone, Copy ja Drop). Toisaalta tämä tekee kielestä yksinkertaisemman ja myös tekee näkyväksi joitakin asioita, jotka C++:ssa ovat näkymättömiä (esimerkiksi kaikki epätriviaalien kopiorakentajien kutsut). 4.5 Makrot Rust-makroista tuntuisi olevan helpompi tehdä luotettavia ja luettavia kuin C-makroista tai C++-malleista. Vaikka macro_rules! on teoriassa melko rajoitettu mekanismi, sillä on kohtuullisen helppoa tehdä melko monimutkaisiakin toiminnallisuuksia ja kutsusyntakseja. Alkuun pääseminen oli kyllä vaikeampaa kuin Schemen syntax-rules:issa, mikä varmaankin johtuu monimutkaisemmasta jäsennyspuusta. 5