Yleistä Erlang Miika Heinonen ja Lassi Uosukainen (Group 92) TIE-20306 Principles of Programming Languages Seminaariessee Erlang on Ericcsonin kehittämä funktionaalinen ohjelmointikieli ja ajoympäristö, joka on julkaistu 1986 ja sen kehitystä jatketaan edelleen. Kielessä on sisäänrakennettu tuki rinnakkaisuudelle, hajauttamiselle ja virheensiedolle. Erlang on nykyään saatavilla vapaan lähdekoodin projektina. Alun perin Erlang kehitettiin useita erilaisia telekommunikaatioprojekteja varten. Siinä on useita muille kielille hankalia tai harvinaisia ominaisuuksia, juurikin telekommunikaatioon pohjautuvien juuriensa vuoksi. Esimerkkinä tästä toimii Erlangin hyvin yksinkertainen rinnakaisuusmalli, joka mahdolistaa yksittäisten ohjelmablokkien ajamisen samanaikaisesti samassa ympäristössä helposti. Rinnakaisuuden lisäksi Erlangin virheenkäsittely mahdollistaa virheiden tunnistamisen ja käsittelyn näiden prosessien sisällä, jopa uuden prosessin toimesta. Erlangin maailmankatsomus Yksi Erlangin kehittäjistä Joe Armstrong tiivistää Erlangin periaatteet seuraavasti:. Prosessit on vahvasti eristetty. Prosessien luomisen ja tuhoamisen tulee olla kevyt operaatio. Viestinvälitys on ainoa tapa, jolla prosessit vaikuttavat toisiinsa. Prosesseilla on uniikit nimet. Jos tiedät prosessin nimen, on sinun voitava lähettää sille viesti. Prosessit eivät jaa keskenään lainkaan resursseja. Virheenkäsittely ei ole paikallista. Prosessit tekevät mitä niiden kuuluukin, tai ne epäonnistuvat. Rinnakkaisuus Yksi yleisimmistä syistä valita Erlang muiden funktionaalisten ohjelmointikielien sijaan on juuri Erlangin kyky käsitellä rinnakkaisuutta ja hajautettua ohjelmointia. Erlang-ohjelmat koostuvat tyypillisesti sadoista tai jopa tuhansista pienistä prosesseista. Rinnakkaisuudella tarkoitetaan ohjelmia, jotka voivat hallita useita suoritussäikeitä samanaikaisesti. Yhtenä esimerkkinä nykyaikaiset käyttöjärjestelmät, jotka mahdollistavat useiden erilaisten ohjelmien ajamisen samanaikaisesti. Erlangissa yksittäisiä suoritussäikeitä kutsutaan prosesseiksi. Prosesseja luodaan Erlangissa spawn-funktiolla. Funktio palauttaa prosessi id:n (pid), jolla identifioidaan kyseinen prosessi ja sen avulla mahdollistetaan prosessin käsittely. Erlangissa käytetään kommunikaatiomallina viestinvälitystä. Prosessit eivät jaa lainkaan muistia keskenään, vaan ne kommunikoivat asynkronisten viestien avulla. Jokaisella prosessilla on oma veistijono, johon sisääntulevat viestit sijoitetaan odottamaan prosessointia. Viestin lähettäminen ei Erlangissa ole estävä operaatio, kun taas vastaanottaminen on. Prosessien välillä kulkevat viestit ovat Erlang termejä. Ne voivat siis olla listoja, tupleja, integereja jne.
Funktionaalisuus Erlang on funktionaalinen ohjelmointikieli. Kuten muissa funktionaalisissa ohjelmointikielissä, suositaan Erlangissa puhtaita funktioita sekä muuttumatonta muistia. Erityisesti kaikki muuttujat ovat Erlangissa muuttamattomia. Tämä tarkoittaa, että Erlangissa muuttujalle voi antaa arvon vain kerran, eikä sitä voi muuttaa sen jälkeen. Tämä on tyypillistä funktionaalisille ohjelmointikielille, joissa muuttuvaa muistia ei usein katsota hyvällä, mutta imperatiiviseen ohjelmointityyliin tottuneelle paradigma on huomattavan erilainen. Muuttujien nimet alkavat Erlangissa aina joko isolla kirjaimella tai alaviivalla. Syy tähän on Erlangin tapa esittää merkkijonoja, eli atomeja. Pienellä kirjaimella alkava merkkijono on Erlangissa merkkijonoliteraali, joten alkukirjain on tapa erottaa muuttujat literaaleista. Erlangissa voi myös käyttää heittomerkkejä, merkkijonoliteraalin merkitsemiseen, mutta pakollista se ei ole. Muita funktionaalisen ohjelmointikielen tunnusmerkkejä Erlangissa on ensimmäisen luokan funktiot. Ensimmäisen luokan funktio tarkoittaa, että kielessä funktioita käsitellään kuten arvoja. Ominaisuus löytyy lähes kaikista funktionaalisista ohjelmointikielistä, mutta myös monista joita ei yleensä käsitetä funktionaalisiksi kieliksi. Käyttökohteet Erlangin suurimpana käyttänä jatkaa edelleen Ericcson, joka käyttää sitä telekommunikaatiojärjestelmien ohjelmointikielenä. Yleisesti Erlangia käytetään hajautettujen ja pehmeän reaaliajan järjestelmien kehittämiseen. Tässä pehmeällä reaaliaikaisuudella tarkoitetaan sitä, että järjestelmä ei anna takuuta suurimmasta mahdollisesta suoritusajasta tietylle operaatiolle, vaan pikemminkin tilastollisen takuun. Esimerkiksi Operaatioon X suorittamiseen kuluu alle 10 ms 96%:ssa tapauksia. Esimerkkejä tämänkaltaisista järjestelmistä ovat juurikin telekommunikaatiojärjestelmien kytkinten ohjaaminen tai protokollien kääntäminen tai web-applikaatioille tarkoitetut palvelimet, kuten IMAP- tai HTTP-palvelimet. Lisäksi Tietokantasovellukset, joissa tarvitaan juuri pehmeän reaaliajan toiminallisuutta ovat yleisiä. Yllämainitun kaltaisiin sovelluksiin Erlang soveltuu monista syistä. Erlang on hyvin vikasietoinen ja tarjoaa virheiden käsittelyyn työkaluja. Useista osista koostuvat ohjelmat hyötyvät taas Erlangin rinnakaisuutta ja viestinvölitystä tukevista ominaisuuksista. Erlangin hajautusmallin ansiosta ohjelmia voidaan ajaa erilaisilla alustoilla, sillä ohjelmien itsessään ei tarvitse tietää olevansa hajautettuja. Tyypitys ja tietotyypit Erlang on vahvasti ja dynaamisesti tyypitetty kieli. Tyypitys tapahtuu dynaamisesti eikä muuttujien tyyppiä tarvitse erikseen määrittää, vain muuttujaan talletetulla arvolla on tyyppi. Tyypin voi kuitenkin halutessaan määrittää. Tyyppiä ei kuitenkaan tarkisteta käännösaikaisesti ilman erillisen työkalun, kuten dialyzerin käyttöä. Vahva tyypitys näkyy kuitenkin siten, että operaatioissa ei voi sekoittaa useampaa eri tietotyyppiä keskenään. Tyyppikonversio on mahdollista ja sitä varten on olemassa useita sisäänrakennetuja funktioita. Kaikkia dataa kutsutaan Erlangissa tietotyypistä riippumatta termeiksi. Tietotyypeistä on käytössä perinteisempien tietottyypien, kuten integerien, stringien ja listojen lisäksi muutamia
erityisempiä tietotyyppejä. Atom on vakio, jolla on nimi. Atomien Pid-tietotyyppiin tallenetaan prosessi id, jonka avulla prosessit voivat vuorovaikuttaa keskenään. Myös porttien identifioimista varten on oma tietotyyppi: Port identifier. Erlangissa on käytössä garbage collection. Se tarkoittaa, että Erlangissa ohjelmoijan ei itse tarvitse kiinnittää huomiota muistin käyttöön, vaan ohjelmointikieli itse vapauttaa käyttämättömän muistin. Ohjelmoija voi itse kutsua garbage collectionin, mutta yleensä se ei ole tarpeellista. Garbage collectionin ennustamattomuus asettaa haasteita Erlangissa, sillä sen ajankohtaa ei voi ennustaa etukäteen. Erlangissa on generational garbage collection. Se tarkoittaa, että muuttujat luokitellaan eri sukupolviin. Muisti, joka on todennäköisemmin vapautunutta kuuluu ensimmäiseen sukupolveen, kun taas muisti joka on ollut käytössä jo pitkään kuuluu korkeampiin sukupolviin. Garbage collection ei varsinaisesti ole Erlangin ominaisuus, vaan Erlangin virtuaalikoneen Beamin, mutta käytännössä Erlangia suoritetaan aina Beamilla. Koska Erlang prosessit eivät jaa muistia, on niillä kaikilla myös oma garbage collection. Erlangin garbage collection käyttää reference collection algoritmia. Siinä muisti oletetaan käytetyksi, mikäli muistiosoitteeseen osoittava osoitin on olemassa. Mikäli muistiin ei ole yhtään osoitinta, ei muistiin voida viitata, joten se voidaan siivota. Erlangin ympäristö OTP (Open Telecom Platform) on kokoelma Erlang-kirjastoja, joiden avulla Erlang taipuu esimerkiksi WWW-palvelimeksi. Suuri osa Erlang-projekteista käyttää itseasiassa Erlang/OTP:ta eli kieltä ja em. Kirjastoja. OTP-kirjastot tarjoavat ratkaisuja useisiin yleisiin verkko- ja kommunikaatioongelmiin. Beam on virtuaalikone, jossa Erlang-koodia suoritetaan. Alunperin Beam on tehty juuri Erlangia varten, mutta nykyään sitä käytetään myös muiden ohjelmointikielten kanssa kuten esimerkiksi Elixir. Käytännön esimerkkejä Erlangin funktionaalisesta luonteesta toimii hyvin esimerkkinä fibonaccin lukujono. Tapauksissa joissa arvo on 0 tai 1 palautetaan sama arvo. Puolipiste lausekkeen perässä tarkoittaa tai, eli suoritusta jatketaan, mikäli arvo ei vastaa ehtoa. Lopuille tapauksille määritellään ehto mitä palautetaan riippuen saadusta arvosta. fibo(0) -> 0 ; fibo(1) -> 1 ; fibo(n) when N > 0 -> fibo(n-1) + fibo(n-2) Esimerkki 1: Fibonacci-funktio Esimerkissä 2 luodaan kaksi prosessia, jotka lähettävät viestejä toisilleen. Ensin luodaan pong - prosessi, jokaa jää odottamaan viestejä muilta prosesseilta. Tähän käytetään avainsanaa receive. Jos saapuva viesti on finished tulostaa ohjelma tiedon tästä ja lopettaa suorituksen. Jos saapuva viesti on muotoa {ping, Ping_PID} tulostetaan tieto tästä ja lähetetään pong prosessille, jolta ping-viesti saatiin. Viestin lähettämiseen käytetään!-operaattoria. Pong-prosessin luonnin
jälkeen luodaan prosessi ping, joka saa pong-prosessin prosessi id:n, jotta voi lähettää edellämainitun viestin. Viestin lähetettyään ping jää vuorostaan odottamaan vastausta ja sen saatuaan tulostaa tiedon. Kun viestin välitystä on suoritettu muuttujassa N määrätyn määrän kutstuaankin ping(0, Pong_PID) -funktiota, joka tulostaan tiedon ohjelman loppumisesta ja lopettaa suorituksen. -module(tut15). -export([start/0, ping/2, pong/0]). ping(0, Pong_PID) -> Pong_PID! finished, io:format("ping finished~n", []); ping(n, Pong_PID) -> Pong_PID! {ping, self()}, receive pong -> io:format("ping received pong~n", []) end, ping(n - 1, Pong_PID). pong() -> receive finished -> io:format("pong finished~n", []); {ping, Ping_PID} -> io:format("pong received ping~n", []), Ping_PID! pong, pong() end. start() -> Pong_PID = spawn(tut15, pong, []), spawn(tut15, ping, [3, Pong_PID]). Esimerkki 2: Kahden prosessin välinen ping-pong Lähteet: https://en.wikipedia.org/wiki/erlang_(programming_language) http://erlang.org/faq/introduction.html https://www.ibm.com/developerworks/library/os-erlang1/index.html https://trigonakis.com/blog/2011/05/26/introduction-to-erlang-message-passing/ http://learnyousomeerlang.com/content