Johdanto. 1. Mikä on ohjelmointikieli?

Samankaltaiset tiedostot
815338A Ohjelmointikielten periaatteet

1. Olio-ohjelmointi 1.1

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

ELM GROUP 04. Teemu Laakso Henrik Talarmo

4. Lausekielinen ohjelmointi 4.1

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Imperatiivisten ohjelmien organisointiparadigmojen. historia

Imperatiivisten ohjelmien organisointiparadigmojen historia

Ohjelmistojen mallintaminen, mallintaminen ja UML

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

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

812341A Olio-ohjelmointi, I Johdanto

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Tietorakenteet ja algoritmit

Johdanto Meta Kielten jaotteluja Historia. Aloitusluento. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

11/20: Konepelti auki

4. Lausekielinen ohjelmointi 4.1

TIE Tietorakenteet ja algoritmit 1. TIE Tietorakenteet ja algoritmit

Lisää pysähtymisaiheisia ongelmia

Tietorakenteet ja algoritmit - syksy

Ohjelmoinnin perusteet Y Python

Ohjelmointi 1. Kumppanit

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Ohjelmoinnin peruskurssien laaja oppimäärä

Tutoriaaliläsnäoloista

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

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

Algoritmit 1. Luento 3 Ti Timo Männikkö

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

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

Bootstrap / HTDP2 / Realm of Racket. Vertailu

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

Maarit Harsu. O h j e l m o i n t i k i e l e t Periaatteet, käsitteet, valintaperusteet

11.4. Context-free kielet 1 / 17

TIE Principles of Programming Languages CEYLON

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python

TT00AA Ohjelmoinnin jatko (TT10S1ECD)

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

Tietueet. Tietueiden määrittely

Ohjelmistojen mallintaminen

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

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

ohjelman arkkitehtuurista.

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia

Luento 1 Tietokonejärjestelmän rakenne

Luento 1 Tietokonejärjestelmän rakenne. Järjestelmän eri tasot Laitteiston nopeus

Osoittimet ja taulukot

Solidity älysopimus ohjelmointi. Sopimus suuntautunut ohjelmointi

ITKP102 Ohjelmointi 1 (6 op)

Imperatiivisen ohjelmoinnin peruskäsitteet. Meidän käyttämän pseudokielen lauseiden syntaksi

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

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

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

Tietorakenteet ja algoritmit

Ongelma(t): Miten mikro-ohjelmoitavaa tietokonetta voisi ohjelmoida kirjoittamatta binääristä (mikro)koodia? Voisiko samalla algoritmin esitystavalla

7/20: Paketti kasassa ensimmäistä kertaa

ADA. Ohjelmointikieli. Ryhmä 5 Henna Olli, Päivi Hietanen

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

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

Haskell ohjelmointikielen tyyppijärjestelmä

Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.

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

811120P Diskreetit rakenteet

T Ohjelmistotekniikan seminaari

Ohjelmoinnin peruskurssien laaja oppimäärä

Java-kielen perusteet

Luento 1 Tietokonejärjestelmän rakenne

ITKP102 Ohjelmointi 1 (6 op)

Luento 1 Tietokonejärjestelmän rakenne. Järjestelmän eri tasot Laitteiston nopeus

Apuja ohjelmointiin» Yleisiä virheitä

etunimi, sukunimi ja opiskelijanumero ja näillä

Osoitin ja viittaus C++:ssa

8/20: Luokat, oliot ja APIt

Ohjelmointi 1 / syksy /20: IDE

Rekursiolause. Laskennan teorian opintopiiri. Sebastian Björkqvist. 23. helmikuuta Tiivistelmä


Lyhyt kertaus osoittimista

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Ongelma(t): Miten jollakin korkeamman tason ohjelmointikielellä esitetty algoritmi saadaan suoritettua mikro-ohjelmoitavalla tietokoneella ja siinä

15. Ohjelmoinnin tekniikkaa 15.1

Ohjelmointikielten kehityshistoriaa

3. Muuttujat ja operaatiot 3.1

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

815338A Ohjelmointikielten periaatteet

Tiina Partanen. Koodaamassa Matikantunnilla

Todistus: Aiemmin esitetyn mukaan jos A ja A ovat rekursiivisesti lueteltavia, niin A on rekursiivinen.

1.3 Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

Älysopimusten kehittäminen. Sopimus suuntautunut ohjelmointi

Ohjelmoinnin peruskurssien laaja oppimäärä

C++ Kuva 1-1. C- ja C++ kielien perustana olevat kielet.

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

815338A Ohjelmointikielten periaatteet Harjoitus 4 vastaukset

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

2. Olio-ohjelmoinista lyhyesti 2.1

Algoritmit 1. Luento 2 Ke Timo Männikkö

Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat. Operaatiot. Imperatiivinen laskenta. Muuttujat. Esimerkkejä: Operaattorit.

Perinteiset tietokoneohjelmat alkavat pääohjelmasta, c:ssä main(), jossa edetään rivi riviltä ja käsky käskyltä.

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

Transkriptio:

Johdanto Ohjelmoinnin opetteluun ei välttämättä tarvitse opiskella lainkaan ohjelmointikieliä: algoritmeja voidaan suunnitella ja analysoida käyttäen matemaattista tai muuta formaalia merkintätapaa. Käytännössä ohjelmoinnin harrastaminen edellyttää ainakin yhden ohjelmointikielen tuntemista. Tällä kurssilla perehdytään ohjelmointikielten arviointi- ja suunnitteluperiaatteisiin sekä kielten ominaispiirteisiin siinä toivossa, että opiskelija oppisi paremmin ymmärtämään käyttämiänsä ohjelmointikieliä ja omaksuisi helpommin uusia kieliä. 1. Mikä on ohjelmointikieli? Ohjelmointikielelle ei ole helppoa antaa tyhjentävää määritelmää. Loudenin ([Lou], s. 3) mukaan ohjelmointikieli on Merkintäjärjestelmä, joka kuvaa laskentaa sellaisessa muodossa, että se on koneen ja ihmisen luettavissa. Tämä määritelmä sisältää termejä, jotka kaipaavat hieman selventämistä: Usein laskenta määritellään formaalisti Turingin koneen avulla; tässä yhteydessä laskennalla kuitenkin tarkoitetaan (väljähkösti) mitä tahansa tietokoneen suorittamaa toimintoa. Se, että ohjelmointikieli on koneen luettavissa tarkoittaa mahdollisuutta kääntää sitä automaattisesti konekielelle. Näin ollen kielen rakenteen on oltava riittävän selkeä ja yksinkertainen. Vaatimus, jonka mukaan kielen on oltava ihmisen luettavissa, on luonnollisesti edellistä vaatimusta epätarkempi. Tämä voidaan tulkita niin, että kielen on sisällettävä joitakin sellaisia abstraktioita, jotka kuvaavat koneen toimintaa niin, että koneen toimintaa ei tarvitse syvällisesti ymmärtää käyttääkseen kieltä. Yleensä ohjelmointikieli muistuttaa myös jossain määrin luonnollista kieltä; on kuitenkin olemassa kieliä, jotka eivät ilmaise ohjelmia merkkijonoina. Nämä kielet ovat tämän kurssin tarkastelujen ulkopuolella. Lopulta voidaan kysyä, miten taataan ohjelman luettavuus kokonaisuutena. Viimeinen vaatimus asettaa kyseenalaiseksi ainakin konekielen ohjelmointikielenä; myös symbolinen konekieli (assembly) on varsin huonosti lukukelpoista ihmiselle, joka

ei tunne tietokoneen sisäistä toimintaa. Yleisesti ottaen yllä oleva määritelmä riittää tämän kurssin tarpeisiin. 2. Miksi tutkia ohjelmointikieliä? Vaikka ohjelmointi onkin monelta osin ongelmien abstrahointia ja ratkaisua, vaikuttaa valittu ohjelmointikieli ja ohjelmoijan käsitys kielestä ongelman ratkaisuun ja ennen kaikkea ratkaisuyritysten implementointitapaan. Sebesta mainitsee kuusi syytä ohjelmointikielten tutkimiseen ([Seb] kappale 1.1). 1. Valmius ilmaista ohjelmointi-ideoita kehittyy ("Increased capacity to express ideas"). o Yleisesti ollaan sitä mieltä, että luonnollisen kielen hallinta vaikuttaa ihmisen ajatteluun. Rajoittunut näkemys käytettävästä kielestä voi vastaavasti rajoittaa ohjelmoinnissa käytettävien kontrollirakenteiden, tietorakenteiden ja abstraktioiden hyödyntämistä. Tyypillinen esimerkki on rekursio, jonka käyttö on mahdollista useissa kielissä; ohjelmoijan on rekursiota käyttäessään tunnettava sen käyttö ja rajoitukset. 2. Tehtävään soveltuvan kielen valinta tehostuu ("Improved background for choosing appropriate languages"). o Kun tunnetaan useita ohjelmointikieliä ja osataan arvioida niitä, voidaan myös paremmin päättää, mikä kieli on asianmukaista valita kulloiseenkin ohjelmointitehtävään. 3. Uusien kielien oppiminen helpottuu ("Increased ability to learn new languages"). o Ainakaan toistaiseksi ohjelmointikielet eivät ole vakiintuneet, vaan koko ajan kehitetään uusia kieliä tehostamaan ohjelmointityötä uudentyyppisten sovellusten rakentamisessa. Uusi kieli on tehokkaampi kuitenkin vain, jos ohjelmoijat oppivat sen nopeasti ja osaavat käyttää kieltä tehokkaasti. Yleisten periaatteiden tuntemus auttaa uuden kielen opiskelussa. 4. Ohjelmointikielen implementoinnin merkitys ymmärretään paremmin ("Better understanding of the significance of implementation"). o Ohjelmointikielten periaatteiden tutkimukseen liittyy myös kielen ominaisuuksien implementointi. Tämän ymmärtäminen auttaa paitsi kielen käyttämisessä, myös virhetilanteiden selvittelyssä. Samoin ohjelman

suorituskyvyn arvioiminen saattaa helpottua, mikäli ohjelmoija ymmärtää käytettävien kirjastofunktioiden sisäistä toimintaa. 5. Tuttujen kielten tehokkaampi käyttö ("Better use of languages that are already known"). o Monet olemassa olevat kielet ovat laajoja ja monimutkaisia eivätkä ohjelmoijat aina tunne käyttämänsä kielen kaikkia ominaisuuksia. Yleisten periaatteiden tuntemus auttaa opettelemaan ja käyttämään tutun kielen ennestään tuntemattomia piirteitä. 6. Tietojenkäsittelyn yleinen edistyminen ("Overall advancement of computing"). o Sebestan mukaan ohjelmointikielten arviointiperiaatteiden tuntemus voi edistää tietojenkäsittelyä yleisestikin. Esimerkiksi nykyisin monet uskovat, että ohjelmoinnissa olisi saavutettu parempia tuloksia, jos ALGOL60 olisi aikoinaan (60 -luvun alkupuolella) syrjäyttänyt FORTRANin. Näin ei kuitenkaan tapahtunut, koska ohjelmistoammattilaiset eivät nähneet ALGOLin etuja FORTRANiin verrattuna. Pratt ([Pra] ss. 4-5) luettelee puolestaan viisi syytä: 1. Käytettävän kielen syvempi ymmärtäminen ("To improve your understanding of the language you are using"). o Vertaa Sebestan listan ensimmäiseen ja neljänteen kohtaan. 2. Tietämys käyttökelpoisista ohjelmointikonstruktioista kasvaa ("To increase your vocabulary of useful programming constructs"). o Tämä liittyy myös Sebestan listan ensimmäiseen kohtaan. 3. Tehtävään soveltuvan kielen valinta tehostuu ("To allow better choice of programming language"). o Sebestan lista kohta 2. 4. Uusien kielien oppiminen helpottuu ("To make it easier to learn a new language"). o Sebestan lista kohta 3. 5. Uusien kielten suunnittelu helpottuu ("To make it easier to design a new language"). Scottin ([Sco], kappale 1.3) mukaan ainakin seuraavista syistä kannattaa perehtyä ohjelmointikielten periaatteisiin:

1. Kielen harvoin käytettyjen ominaisuuksien ymmärtäminen paranee ( Understand obscure features ). o Sebestan lista kohta 5. 2. Mahdollisuus valita sopivin vaihtoehtoisista toteutustavoista ("Choose among alternative ways to express things"). o Vertaa Sebestan listan ensimmäiseen kohtaan. 3. Ohjelmoinnin oheistyökalujen käyttö tehostuu ("Make good use of debuggers, assemblers, linkers, and related tools"). o Hankalien ohjelmointivirheiden jäljittäminen saattaa olla helpompaa, jos tuntee kielen toteutuksen yksityiskohtaisesti. 4. Kieleen kuulumattomien ominaisuuksien simulointi helpottuu ("Simulate useful features in languages that lack them"). o Erityisesti vanhemmista kielistä puuttuu monia nykyään yleisiä ominaisuuksia, joita asiantunteva ohjelmoija voi kuitenkin jäljitellä niin, että koodi säilyy luettavana. 5. Ohjelmointikieliteknologian yleinen soveltaminen ("Make better use of language technology wherever it appears") o Ohjelmointikielten periaatteiden tunteminen helpottaa kirjoittamaan ohjelmia, joiden pitää jäsentää ja käsitellä strukturoitua dataa. Yhteenvetona voidaan todeta, että "tavallisenkin" ohjelmoijan kannalta on hyödyllistä opiskella ohjelmointikielten periaatteita ainakin seuraavista syistä: 1. Ohjelmointitaito kehittyy. o Ohjelmoija osaa käyttää ohjelmointirakenteita kielen mukaisesti ja ymmärtää kielen implementoinnin vaikutukset ohjelmaan. Lisäksi virheiden etsiminen ja korjaaminen helpottuu. 2. Valmius oppia uusia kieliä kasvaa. o Useimpien ohjelmoijien on jossain vaiheessa opeteltava uusi kieli jotain erikoistehtävää varten; kielten perusperiaatteiden tunteminen antaa valmiuden tähän. Lisäksi ohjelmoinnin opettajien on syytä tuntea kielten periaatteet.

3. Ohjelmointiparadigmat Ohjelmointikieliä on monta eri tyyppiä; kielen tyyppi on läheisessä yhteydessä ohjelmointitapaan, paradigmaan. Ohjelmoinnissa paradigma koostuu laskennallisesta mallista, käsitteistöstä ja välineistöstä ([Har], s. 15). Ylätasolla kielet voidaan jaotella imperatiivisiin (käskykielet) ja deklaratiivisiin (esittelykielet). Paradigman mukainen kielten luokittelu ei ole aina helppoa: kielissä saattaa olla useiden ohjelmointiparadigmojen piirteitä. Paradigmojen luokittelujakin on monia. Luonnollisin ohjelmointiparadigma von Neumann -tietokoneympäristössä (ks. johdannon kappale 5) on imperatiivinen ohjelmointi. Imperatiivisen ohjelmoinnin tunnuspiirteet ovat 1. muistipaikkoja mallintavat muuttujat, 2. sijoituslauseet, joiden avulla muistia manipuloidaan ja 3. komentojen peräkkäinen suorittaminen. Edellä mainittua ohjelmointitapaa tukevia kieliä kutsutaan yleensä imperatiivisiksi kieliksi. Ei ole yllättävää, että nykykielistä valtaosa on (ainakin jossakin mielessä) imperatiivisia. Usein olio-ohjelmointi (ks. esimerkiksi [Lou] s. 14) lasketaan omaksi ohjelmointiparadigmakseen ja se vaatiikin kieleltä tukea luokkien esittämiselle; useimmat nykyisistä oliokielistä ovat kuitenkin luonteeltaan imperatiivisia ja niillä ohjelmoiminen on pitkälle imperatiivisen paradigman mukaista. Tosin nykyisiin valtakieliin on viime aikoina sisällytetty piirteitä myös muista paradigmoista, erityisesti funktionaalisesta ohjelmoinnista. Olio-ohjelmointi edellyttää joka tapauksessa siihen soveltuvaa ajattelutapaa, joten sitä voidaan perustellusti kutsua ohjelmointiparadigmaksi. Rinnakkainen ohjelmointi poikkeaa imperatiivisesta ohjelmoinnista sikäli, että siinä voidaan määritellä samanaikaisesti suoritettavia toimenpiteitä, jolloin pitää huolehtia muuttujien päivittämisen ja suoritettavien prosessien kommunikoinnin synkronoimisesta. Monet nykyiset olio-ohjelmointikielet tukevat rinnakkaisuutta. Deklaratiivisen ohjelmointiparadigman antamia vaihtoehtoja imperatiiviselle ohjelmoinnille ovat funktionaalinen ohjelmointi (funktio-ohjelmointi) ja logiikkaohjelmointi. Myös tietokantakielet lasketaan kuuluvaksi deklaratiiviseen

paradigmaan. Funktionaalinen ohjelmointi perustaa laskennan funktioiden soveltamiseen (application of functions) annettuihin parametreihin; tästä syystä funktionaaliset ohjelmointikielet tunnetaan myös englanninkielisellä nimellä applicative languages. Funktionaalisen ohjelmointikielen perusmekanismi on siten funktiokutsu. Tämä ilmenee havainnollisesti toistorakenteen toteuttamisessa: funktionaalisessa kielessä toisto toteutetaan funktion rekursiivisella kutsulla. Imperatiiviseen ohjelmointiin tottuneelle voi olla vaikea hahmottaa funktionaalista ohjelmointia, koska siinä ei käytetä muuttujia tai toistorakenteita. Tunnetuin funktionaalinen ohjelmointikieli on epäilemättä LISP, josta on olemassa monia murteita. Viime vuosina Haskell on myös kasvattanut suosiotaan. Logiikkaohjelmointi pohjautuu symbolisen logiikan käyttöön; logiikkaohjelmointikielessä ohjelma koostuu väitteistä (statements), jotka kuvaavat totuuksia. Puhtaassa logiikkaohjelmointikielessä ei tarvita kontrollirakenteita, mistä syystä joissakin lähteissä pelkästään logiikkaohjelmointia kutsutaan deklaratiiviseksi eli kuvausohjelmoinniksi (ominaisuudet esitellään, mutta suoritusjärjestystä ei anneta [Lou] s. 14, [Seb] kappale 16.4). Logiikkaohjelmoinnissa käytetään yleisesti arvojen esittämiseen muuttujia, mutta ne poikkeavat imperatiivisen ohjelmoinnin muuttujista siten, että ne eivät mallinna muistialueita vaan käyttäytyvät pikemminkin matematiikassa käytettävien muuttujien lailla, ts. ovat nimiä tuloksille. Prolog on selvästi tunnetuin logiikkaohjelmointikieli. 4. Ohjelmointikielten suunnittelu- ja arviointikriteerejä Tällä kurssilla pyritään arvioimaan olemassa olevia ohjelmointikieliä. Tätä varten tarvitaan periaatteita, joiden avulla kieliä voidaan arvostella. Samat kriteerit ovat tärkeitä myös ohjelmointikielien suunnittelussa. Uuden ohjelmointikielen luominen on erittäin vaikea tehtävä, siitäkin syystä, että tietojenkäsittelytieteilijät eivät ole yksimielisiä kaikista käytettävistä arviointiperiaatteista ja etenkään niiden tärkeysjärjestyksestä. Seuraavassa esitetään joitakin perusperiaatteita, jotka ovat yleisesti hyväksyttyjä. Ohjelmointikielten syntyaikoina tietokoneet olivat hitaita ja tehottomia nykyisiin verrattuna. Siksi ensimmäisten korkean tason ohjelmointikielten suunnittelussa

ylivoimaisesti tärkein suunnitteluperiaate oli tehokkuus. Tämän vuoksi 1950-luvulla syntynyt FORTRAN suunniteltiin muistuttamaan mahdollisimman paljon konekieltä. Noista ajoista laitteet ovat kehittyneet valtavasti ja tietokoneita käytetään yhä useammanlaisiin tehtäviin, jolloin myös ohjelmointikieliä on alettu suunnitella erikoistarkoituksiin. Tämän myötä arviointikriteeritkin ovat monimutkaistuneet. C.A.R. Hoare [Hoa], esitti kriteeristön ohjelmointikielten arviointiin 1970-luvun alkupuolella. Hänen mukaansa ohjelmointikielen tulee tukea ohjelmoijaa erityisesti ohjelman suunnittelussa, dokumentoinnissa ja virheiden etsimisessä sekä korjaamisessa. Hoare esittää, että objektiiviset periaatteet hyvän ohjelmointikielen suunnitteluun voidaan koota viiteen termiin: 1. Yksinkertaisuus (Simplicity) 2. Turvallisuus (Security) 3. Nopea käännettävyys (Fast translation) 4. Käännetyn ohjelmakoodin tehokkuus (Efficient object code) 5. Luettavuus (Readibility) Tarkastellaan lähemmin Loudenin ([Lou], Luku 3) listaaman ominaisuusjoukon ominaisuuksia. Loudenin kriteerit ovat: 1. Tehokkuus (Efficiency) 2. Yleisyys (Generality) 3. Ortogonaalisuus (Orthogonality) 4. Sisäinen yhdenmukaisuus (Uniformity) 5. Yksinkertaisuus (Simplicity) 6. Ilmaisuvoima (Expressiveness) 7. Täsmällisyys (Preciseness) 8. Laiteriippumattomuus (Machine independence) 9. Turvallisuus (Security) 10. Yhdenmukaisuus yleisesti käytettyjen merkintöjen ja sopimusten kanssa (Consistency with accepted notations and conventions) 11. Laajennettavuus (Extensibility) 12. Rajoitettavuus (Restrictability) Tehokkuus voidaan jakaa useaan osaan. Yksi tärkeimmistä tehokkuuden mittareista on (ja oli varsinkin tietokoneiden nuoruusvuosina) käännetyn koodin tehokkuus. Tämä

sisältyykin Hoaren listaan sellaisenaan. Joskus puhutaan myös kääntäjän kyvystä optimoida tuottamaansa konekielistä koodia. Esimerkiksi alustetut vakiomuuttujat voidaan sijoittaa arvoina koodiin jo käännösvaiheessa. Käännöksen tehokkuudella tarkoitetaan kielen kykyä sallia ohjelman konekielisen koodin tuottamisen nopeasti ja kohtuullisen kokoisella kääntäjäohjelmalla. Joissakin kielissä on ominaisuuksia, joita on hyvin vaikea tarkistaa käännösaikaisesti: Jos kääntäjä tarkastaa säännön, siitä voi tulla tehoton, jos taas jättää tarkastamatta, rikotaan luotettavuuden periaatetta. Lisäksi voidaan tarkastella kielellä ohjelmoimisen tehokkuutta: Kuinka nopeasti voidaan tuottaa hyödyllisiä ohjelmia kieltä käyttämällä? Tämä liittyy läheisesti kielen ilmaisuvoimaan: Periaatteessa ilmaisuvoimaisella kielellä voidaan kirjoittaa tehokkaammin ohjelmia, mutta toisaalta sellainen kieli on yleensä monimutkaisempi ja hitaampi oppia. Yleisyys, ortogonaalisuus ja sisäinen yhdenmukaisuus liittyvät läheisesti ohjelmointikielen rakenteisiin. Yleisyys tarkoittaa kielen ominaisuutta koota ominaisuutensa muutamista peruskäsitteistä. Esimerkiksi Pascal-kielessä on kahdentyyppisiä aliohjelmia - PROCEDURE (eivät palauta arvoa) ja FUNCTION (palauttavat arvon). Sen sijaan C- kielessä käytetään vain yhtä tyyppiä olevia funktioita, joilla voidaan toteuttaa molemmat toiminnot. Tässä mielessä C on yleisempi kuin Pascal. Ortogonaalisuus kytkeytyy yksinkertaisuuteen: ortogonaalisuudella tarkoitetaan kielen piirteiden riippumattomuutta toisistaan, kielessä pitäisi olla mahdollisimman vähän perusrakenteita, joita voidaan yhdistellä toisistaan riippumatta. Tällöin mikä tahansa yhdistelmä on laillinen ja merkityksellinen. Esimerkki ortogonaalisuuden puutteesta C -kielessä: Kielessä voidaan käyttää taulukoita (array) ja tietueita (struct). Tietue voi olla funktion paluuarvona, mutta taulukko ei voi olla. ALGOL68- kielen suunnittelussa käytettiin pääperiaatteena ortogonaalisuutta. Jokaisella lauseen rakenteella on tyyppi ja tyyppejä voi yhdistellä rajoituksetta. Tällaisen kielen ongelmaksi muodostuu se, että kieli sallii erittäin monimutkaiset rakenteet. Sisäinen yhdenmukaisuus vaatii johdonmukaisuutta kielen rakenteiden ulkoasussa ja käyttäytymisessä. Yhdenmukaisuutta voidaan rikkoa kahdella tavalla: Joko samankaltaisesti käyttäytyvät asiat näyttävät erilaisilta tai samalta näyttävät asiat käyttäytyvät eri lailla. Esimerkiksi funktion paluuarvo näyttää Pascalissa sijoituslauseelta: FUNCTION fun : Integer; begin fun := 10; end;

Yksinkertaisuutta pidettiin aikoinaan yhtenä tärkeimmistä suunnitteluperiaatteista. Esimerkiksi Pascal-kielessä se on ollut voimakkaana kriteerinä kieltä konstruoitaessa vastapainona ALGOL68- ja PL/I- kielten monimutkaisuudelle. Yksinkertaisuus on yllättävän vaikea saavuttaa, koska se sotii monia muita tavoiteltavia asioita vastaan. Lisäksi yksinkertaisen kielen käyttäminen voi olla vaikeata. Esimerkiksi BASIC-kieli on erittäin yksinkertainen, mutta sillä on vaikeata rakentaa suuria ohjelmia puutteittensa takia. (BASICista puuttuu lohkorakenne ja mahdollisuus esitellä muuttujia jne). Ylenmääräinen yksinkertaisuus ohjelmointikielessä rajoittaa sen ilmaisuvoimaa. Ilmaisuvoima auttaa ohjelmoijaa tuottamaan ohjelmia tehokkaammin, sen avulla kuvataan, kuinka helppoa kielessä on ilmaista monimutkaisia toimintoja ja rakenteita. Rekursion salliminen on tyypillinen seikka, joka lisää kielen ilmaisuvoimaa. (Kirjoita esimerkiksi ensin rekursiivinen Quicksort- toteutus ja sitten toteutus ilman rekursiota!) Ilmaisuvoiman kasvu on yleensä ristiriidassa yksinkertaisuuden kanssa, koska ilmaisuvoiman lisääminen vaatii kieleen uusia piirteitä ja rakenteita. Nykyisissä ohjelmointikielissä ilmaisuvoimaa pyritään parantamaan erilaisia rakenteita sisältävien kirjastojen avulla; näiden tunteminen ei ole välttämätöntä kielen käyttämisen kannalta. Ilmaisuvoimana voidaan myös pitää kielen kykyä ilmaista operaatioita lyhyesti. Tässä mielessä C on ilmaisuvoimainen kieli, esimerkiksi C-kielinen funktio strcpy(char *s, char *t) { while( *s++ = *t++); } kopioi merkkijonon toiseen. Koodi on lyhyt, mutta monen mielestä hankalahkoa luettavaa. Täsmällisyys merkitsee sitä, että kielellä on tarkka määrittely. Täsmällisyyden vaatimuksesta seuraa, että kielen käyttäytyminen on ennustettavaa ja se lisää kielen luotettavuutta. Laiteriippumattomuus saavutetaan pääasiassa käyttämällä kielessä tietotyyppejä, jotka eivät vaadi koneen sisäisen muistinvarauksen tai arkkitehtuurin sisäisten ominaisuuksien tuntemusta. C- kielessä int- tyyppinen muuttuja voi olla ympäristöstä riippuen joko 16- tai 32- bittinen luku. Sen sijaan Java- kielen int on aina 32- bittinen. Näin ollen tässä suhteessa Java on laiteriippumattomampi kuin C.

Turvallisuus liittyy läheisesti täsmällisyyteen ja luotettavuuteen ja se kuvaa suunnitteluperiaatetta, joka sekä estää ohjelmointivirheiden (sekä syntaktisten että semanttisten) syntymistä että edistää niiden havaitsemista. Turvallisuusperiaate johti kielten suunnittelijat luomaan tyyppikäsitteen ja tyypin tarkistuksen sekä muuttujien esittelyn. Turvallisuus on siten ristiriidassa kielen ilmaisuvoiman ja yksinkertaisuuden kanssa. Kokeneen ohjelmoijan tulisi kyetä helposti oppimaan ja käyttämään ohjelmointikieltä. Mitä standardimaisempia ratkaisuja käytetään, sitä helpommin niitä hyödynnetään. Tätä edistää yhdenmukaisuus yleisesti käytettyjen merkintöjen ja sopimusten kanssa. Tämän periaatteen rikkominen voi johtaa myös turvallisuusongelmiin, esimerkiksi nykyajan ohjelmoija tekee helposti havaitsemattomia virheitä koodatessaan FORTRANkielellä, koska se ei erottele välilyöntejä. Toistolause, joka tulostaa luvut yhdestä kymmeneen voidaan kirjoittaa FORTRANilla seuraavasti: DO 100 I= 1,10 PRINT *,'I =',I 100 CONTINUE Jos kuitenkin kirjoitetaan (vahingossa) DO 100 I= 1 10 PRINT *,'I =',I 100 CONTINUE tuloksena onkin ensimmäisenä operaationa sijoittaa muuttujaan DO100I arvo 110. Laajennettavuus sanoo, että tulisi olla jokin yleinen mekanismi, jonka avulla kieleen voidaan lisätä ominaisuuksia. Mitä uusien ominaisuuksien lisääminen tarkoittaa, vaihtelee näkökulmasta riippuen. Esimerkiksi useimmissa kielissä voi määritellä uusia tietotyyppejä ja nykyisiin olio-ohjelmointikieliin on mahdollista lisätä luokkia kirjoittamalla uusia luokkakirjastoja. Joihinkin kieliin, kuten funktionaalisiin kieliin luettavaan LISPiin, voidaan vaikuttaa syvemminkin, esimerkiksi lisäämällä uusia piirteitä kääntäjätasolle. Tavallisimmissa ns. imperatiivisissa kielissä tällainen ei ole niin helppoa. Rajoitettavuus tarkoittaa, että ohjelmoijan tulisi pystyä käyttämään ohjelmointikieltä hyödyllisesti, vaikka tunteekin vain osan kielen ominaisuuksista ja rakenteista. Esimerkiksi Java-ohjelmoijana saattaa toimia vuosiakin ilman Javan rinnakkaisuuden

tuntemusta. Rajoitettavuuden vaatimusta on kuitenkin kritisoitu varsin voimakkaasti, koska se voi johtaa ohjelmoijalle käsittämättömiin virhetilanteisiin. Sebesta ([Seb], kappale 1.3) käsittelee ainoastaan kielten arviointiperiaatteita, jotka jaetaan neljään pääkategoriaan (luettavuus, kirjoitettavuus, luotettavuus ja resurssivaatimukset). Pääkategorioiden kriteereihin vaikuttavat seuraavat ominaisuudet: 1. Luettavuus (Readibility) i. Yksinkertaisuus (Simplicity) ii. Ortogonaalisuus (Orthogonality) iii. Tietotyypit (Data types) iv. Syntaksi (Syntax design) 2. Kirjoitettavuus (Writability) i. Edelliset ja ii. Abstraktiotuki (Support for abstraction) iii. Ilmaisuvoima (Expressivity) 3. Luotettavuus (Reliability) i. Edelliset ja ii. Tyypin tarkistus (Type checking) iii. Poikkeusten käsittely (Exception handling) iv. Moninimisyys (Aliasing) 4. Resurssivaatimukset (cost) Sebesta korostaa erikseen kielen luettavuutta yhtenä tärkeimmistä kriteereistä. Hänen listassaan luettavuus sisältää piirteitä Loudenin listasta (yksinkertaisuus ja ortogonaalisuus). Tietotyypit liittyvät puolestaan kielen ilmaisuvoimaan, ts. sen kykyyn esittää abstraktioita erilaisista tyypeistä ja rakenteista. Syntaksin vaikutuksesta luettavuuteen Sebesta mainitsee erikoissanat (special words) sekä muodon ja merkityksen (form and meaning). Vanhemmissa kielissä rajoitettiin muuttujien nimien pituutta, jolloin niille ei voinut antaa kuvaavia nimiä. Tämä huonontaa kielen luettavuutta. Erityisen voimakkaasti kielen ulkoiseen luettavuuteen vaikuttavat sen erikoissanat (esimerkiksi kontrollirakenteiden while, for,if ja else ). Lausekkeiden kirjoittaminen niin, että niiden muodosta käy niiden tarkoitus selville on ilmeinen luettavuutta tukeva tekijä.

Kielen kirjoitettavuuteen - joka arvioi, kuinka helposti kielellä voi tuottaa valitun sovellusalueen ohjelmia - vaikuttaa samankaltaisia tekijöitä kuin luettavuuteenkin. Mikäli kielessä on suuri määrä piirteitä, ohjelmoija ei tunne niitä kaikkia syvällisesti ja voi siten tahtomattaan käyttää niitä virheellisesti. Näin ollen yksinkertaisuus ja piirteiden yhdisteltävyys (ortogonaalisuus) edesauttavat kirjoitettavuutta. Toisaalta liiallinenkin ortogonaalisuus voi haitata kirjoitettavuutta, koska tällöin piirteitä voidaan yhdistellä virheellisesti sitä huomaamatta. Mahdollisuus abstrahointiin on tärkeimpiä piirteitä nykyisissä ohjelmointikielissä, koska käytettävät suunnittelumetodit perustuvat tietorakenteiden valintaan niin, että ne esittävät ohjelmointiongelman piirteitä käsitteellistettynä. Näin ollen kielen tapa tukea abstraktiota vaikuttaa suuresti sen kirjoitettavuuteen. Vanhemmissa kielissä, kuten FORTRANissa, oli monimutkaisemmat tietorakenteet esitettävä epäluonnollisella tavalla, esimerkiksi taulukoita käyttämällä. Kielet, joissa on mahdollisuus määritellä omia tietorakenteita, sallivat näitä käsittelevän koodin huomattavasti luonnollisemman kirjoitusasun. Kielen ilmaisuvoima on monitahoinen käsite, kuten edellä on tullut esiin. Se voi tarkoittaa mahdollisuutta monimutkaisen ohjelman rakentamiseen pienellä vaivalla käyttämällä vahvoja operaattoreita, kuten APL-kielen matriisioperaattorit. Usein sillä tarkoitetaan, että kielessä on mahdollisuus ilmaista operaatioita lyhyesti, kuten aiemmin esitetyssä C-kielisessä strcpy-funktiossa. Ilmaisuvoiman lisääminen lisää myös kielen kirjoitettavuutta, mutta ei aina luettavuutta. Luotettavuudella tarkoitetaan kielen käyttäytymistä määritellyllä tavalla kaikissa tilanteissa. Sekä luettavuus että kirjoitettavuus vaikuttavat luotettavuuteen. Niiden lisäksi Sebesta käsittelee kolmea listassa mainittua luotettavuuteen liittyvää piirrettä. Tyypin tarkistus tarkoittaa tyyppivirheiden tarkistusta ohjelmassa, ts. sen tarkistamista, että tietyntyyppiseen muuttujaan sijoitetaan vain muodoltaan asianmukaista tietoa. Tyypin tarkistus vaikuttaa voimakkaasti kielen luotettavuuteen. Tarkistus voi tapahtua käännösaikaisesti tai ajonaikaisesti. Koska ajonaikainen tarkistus on resursseja vaativaa, pyritään pääasiassa käännösaikaiseen tarkistukseen; muutenkin on suotavaa havaita tämän kaltaiset virheet ohjelmasta mahdollisimman varhain. Poikkeusten käsittelyllä tarkoitetaan kielen kykyä havaita ajonaikaiset virheet ja mahdollisesti toipua niistä; tämä on myös kielen luotettavuuteen vahvasti vaikuttava

ominaisuus. Nykykielissä (kuten Java, C++ ja C#) onkin yleensä olemassa laaja poikkeusten käsittelymekanismi. Vanhemmista kielistä se sen sijaan usein puuttuu. Moninimisyydellä (aliasing) tarkoitetaan väljästi kielen kykyä muodostaa kaksi eri muuttujaa viittaamaan samaan muistipaikkaan. Tämä on yleensä mahdollista kielissä, joissa voidaan käyttää osoittimia. Moninimisyyttä pidetään yleensä varsin vaarallisena piirteenä kielessä, esimerkiksi C-ohjelmassa int a=10, b=15; int *pa,*pb; pa = &a; *pa = 20; pb = pa; *pb = b; printf("a = %d, b = %d", a,b); ei ensi silmäyksellä ehkä huomaa muuttavansa muuttujan a arvoa. Kuitenkin tulostuu a = 15, b = 15 Joissakin kielissä rajoitetaan moninimisyyttä luotettavuuden lisäämiseen. Viimeisenä arviointikriteerinä Sebesta mainitsee kielen resurssivaatimukset. Nämä muodostuvat useista eri osa-alueista. Aluksi tarvitaan resursseja kouluttamaan ohjelmoijia käyttämään kieltä: tähän vaikuttaa mm. kielen yksinkertaisuus ja samankaltaisuus muiden kielten kanssa. Toiseksi ohjelman kirjoittaminen vaatii resursseja; näiden resurssien tarve riippuu kielen kirjoitettavuudesta (sovellusalueen suhteen). Myös kääntämisen tehokkuus ja ohjelmien suorittamisen tehokkuus vaikuttavat tarvittaviin resursseihin, samoin implementointijärjestelmän kustannukset. Useimmat Java-ohjelmat voidaan tuottaa täysin ilmaisilla työkaluilla, sen sijaan esimerkiksi C++:lla toteutetun Windows-ohjelman implementointi voi olla hankalaa ilman jonkin ohjelmointiympäristön hankkimista. Huonon luotettavuuden aiheuttamat kustannukset ja ylläpidon vaatimat resurssit voidaan Sebestan mukaan myös laskea kielen resurssivaatimuksiin. Maarit Harsu esittelee lyhyesti ohjelmointikielen suunnitteluun vaikuttavia kriteerejä lähinnä Sebestan arviointiperusteiden pohjalta ([Har], 1.6. Ohjelmointikielen suunnittelu).

5. Ohjelmointikielten suunnitteluun vaikuttavia tekijöitä Edellisessä kappaleessa mainittujen kriteerien lisäksi kielten suunnitteluun vaikuttaa muitakin seikkoja. Yksi keskeisimmistä tällaisista seikoista on tietokoneen arkkitehtuuri. Koko tietokoneiden historian ajan vallitseva arkkitehtuurityyppi on ollut ns. von Neumannin arkkitehtuuri. Lähes kaikki nykyiset tietokoneet on suunniteltu tämän periaatteen mukaisesti; von Neumannin tietokoneessa sekä data että ohjelma tallennetaan samaan muistiin, eikä niitä voi erottaa toisistaan. Ohjelman muistialue: DATA KÄSKYT... Laskennan tulokset Käskyt ja data CPU Aritmeettislooginen yksikkö (ALU) Kontrolliyksikkö Käskyjen dekoodaus IO Kuva. von Neumannin tietokonearkkitehtuuri Keskusyksikkö (CPU, central processing unit) on muistista erillään ja suorittaa käskyt, minkä vuoksi käskyt ja data pitää siirtää muistista keskusyksikköön. Lisäksi laskennan tulokset on siirrettävä takaisin muistiin. Siirtämisen nopeus rajoittaa ohjelman suorituksen nopeutta, tätä ilmiötä sanotaan von Neumannin pullonkaulaksi (von Neumann bottleneck).

Itse asiassa von Neumannin arkkitehtuurin käyttöönotto johtikin ohjelmointikielten syntymiseen, kun oli mahdollista manipuloida tietokoneohjelmia samaan tapaan kuin dataa. Suurin osa nykyisistä ohjelmointikielistä onkin suunniteltu silmälläpitäen von Neumannin arkkitehtuuria. Kuten jo aiemmin mainittiin, tällaisia kieliä sanotaan imperatiivisiksi ohjelmointikieliksi. Imperatiivisen ohjelmointikielen tyypillisiä piirteitä ovat: muistia mallintavat muuttujat, sijoituslauseet, joiden avulla muistia manipuloidaan, komentojen peräkkäinen suorittaminen, toiston iteratiivinen muoto (rekursion vastapainona). Funktionaalisessa kielessä laskenta pohjautuu pääasiassa funktion soveltamiseen annettuihin parametreihin ilman sijoituslauseita ja iteraatiota. Tietojenkäsittelytieteilijät pitävät funktionaalisia kieliä monessa suhteessa parempina kuin imperatiivisia, mutta ne eivät ole nykyisessä tietokonearkkitehtuurissa niin tehokkaita kuin imperatiiviset kielet, joten ne eivät ole ainakaan toistaiseksi niin yleisiä kuin imperatiiviset kielet. Myös ohjelmistojen suunnitteluperiaatteet vaikuttavat voimakkaasti ohjelmointikielten suunnitteluun. Ensimmäiset (korkean tason) ohjelmointikielet syntyivät 1950 -luvun loppupuolella; tällöin osoitettiin että "automaattinen ohjelmointi" oli mahdollista. Näihin aikoihin luotiin vielä nykyäänkin käytössä oleva FORTRAN-kieli. 1960-luvulla luotiin satoja uusia ohjelmointikieliä eri periaatteiden nojalla; vuosikymmentä onkin sanottu Baabelin tornin ajaksi ([Kai], sivu 12). Kun siirryttiin 1970-luvulle, rakenteellinen ohjelmointi nousi pääperiaatteeksi ohjelmistojen suunnittelussa ja tällä vuosikymmenellä kehitetyt kielet ovatkin pääasiassa suunniteltu rakenteellisen ohjelmoinnin tarpeisiin. Antti-Juhani Kaijanahon ([Kai], sivu 13) mukaan 1970-luvun aikana onkin kehitetty merkittävimmät ideat ohjelmointikielten suunnittelussa, tämän jälkeen kielten kehitys on ollut maltillisempaa. Rakenteellisen ohjelmoinnin päämetodeiksi muodostuivat ylätasolta lähtevä suunnittelu (top-down design) ja askeleittain tarkentaminen (stepwise refinement). Käytettyjen ohjelmointikielten puutteiksi havaittiin tyypin tarkistuksen epätäydellisyys ja kontrollilauseiden puutteet (esimerkiksi goto -lausetta alettiin pitää haitallisena).

1970-luvun loppupuolella prosessiorientoitunut suunnittelumalli alkoi antaa tietä dataorientoituneelle mallille. Tämä johti aluksi abstraktien tietotyyppien käyttöönottoon ja lopulta olio-ohjelmoinnin syntymiseen. Olio-ohjelmointia tukevia kieliä alkoi ilmestyä 1980-luvulla (vaikka ajatuksena se ei olekaan niin uusi). Olioohjelmointikielten valta-asema osoittaa dataorientoituneen suunnittelumallin vallitsevuutta. Prosessiorientoitunut suunnittelukin on kuitenkin lyönyt leimansa nykykieliin sikäli, että monet valtakielistä (esimerkiksi Java ja C#, nykyään myös C++) tukevat rinnakkaisuutta. Lähteet [Har] Harsu, Maarit. Ohjelmointikielet. Periaatteet, käsitteet, valintaperusteet, Talentum 2005. [Hoa] Hoare, C.A.R. Hints on Programming Language Design, in C.A.R: Hoare and C.B. Jones, Essays in Computer Science, Prentice Hall 1989. [Kai] Kaijanaho, Antti-Juhani. Ohjelmointikielten periaatteet, Opetusmoniste, Jyväskylä 2010, URL: http://users.jyu.fi/~antkaij/opetus/okp/2012/okp-moniste.pdf, viitattu 27.11.2014. [Lou] Louden, Kenneth C. Programming Languages, Principles and Practice, PWS-KENT 1993. [Pra] Pratt, Terrence W. Programming Languages, Design and Implementation, Second edition, Prentice Hall 1984. [Sco] Scott, Michael L. Programming Language Pragmatics 2nd edition, Elsevier 2006. [Seb] Sebesta, Robert W. Concepts of Programming Languages 10th edition, Pearson 2013.