maanantai 12. tammikuuta 2009

Luento 1 - kielien moninaisuudesta ja luokittelusta

Ohjelmointikielten periaatteet, Jyväskylän yliopiston kurssikoodiltaan TIES542, kurssin suositeltavin suoritustapa on oppimispäiväkirjan kirjoittaminen, jota tässä paraikaa kirjoitan. Tämä sinällään on virkistävä, ainutlaatuinen kokemus ja toivon kehittyväni "päiväkirjailijana" kurssin kuluessa.

Taustoistani voisin mainita sen verran, että olen ohjelmoinut kaikenlaista pientä aina ala-asteikäisestä lähtien. Varsinainen "valaistuminen" ohjelmoinnin suhteen tapahtui tosin vasta yliopisto-opintojeni alkuvaiheessa käytyäni Ohjelmointi 2 sekä GKO-kurssit. Voisi sanoa, että tämän jälkeen maailma ei ole ollut entisensä.

Sittemmin useat eri kielet, mukaan lukien Perl, PHP, Python ja Lua, ovat tulleet enemmän tai vähemmän tutuiksi. Erityisesti olen tykästynyt Pythoniin sen joustavuuden ja mukavan syntaksin vuoksi. Funktiokielet ovat toistaiseksi jääneet vähemmälle huomiolle. Osallistun kurssille avoimin mielin ja toivon kurssin jälkeen hahmottavani ohjelmointikieliä hieman laajemmasta näkökulmasta.

Luennolla listattiin yleisön tuntemia ohjelmointikieliä. Suuren osan tunsin ainakin nimeltä. Kenties yllättävimmät listatut kielet olivat laitteenohjaukseen käytettävä LabView sekä COMMAND.COM, jota en ollut aiemmin hahmottanut ohjelmointikielenä. LabView herätti kiinnostukseni erityisesti, koska mainittiin, että kyseessä on graafinen ohjelmointityökalu. Wikipedian sivulta varmistin, että kyseessä on tietovuoarkkitehtuuriin pohjautuva kieli.

Tietovuoarkkitehtuuriin pohjautuvat järjestelmät ovat sydäntäni lähellä. Olenhan jo useita vuosia työskennellyt niiden parissa erityisesti Blenderiin liittyen. Useat grafiikan ja äänen käsittelyyn ohjelmistot hyödyntävät kyseistä arkkitehtuuria. Paraikaa kehitän/suunnittelen omaa pientä ohjelmistoani. Mielestäni tietovuolähestymistapa tarjoaa joissain tapauksissa oivan vaihtoehdon perinteisille, tekstipohjaisille kielille. Linux.com listaakin eräitä graafisia "lasten" ohjelmointikieliä ("lasten" koska mikään ei kiellä ainakaan testaamasta noita).

Veikkaisin, että graafisten kielten rajat tulevat vastaan kompleksisuuden hallinnassa. Tämä sinällään on jokaisen ohjelmoijan perustehtävä. Miksi muuten ohjelmointikieliä olisi ylipäätään kehitetty? Nähdäkseni kukin kieli pyrkii luomaan tehtäväkenttään mahdollisimman hyvin sopivan abstraktion. Toki kielen luonnissa otetaan muitakin aspekteja huomioon. Kuitenkin kullakin kielellä nähdäkseni on jokin perustehtävä, jonka se pyrkii täyttämään mahdollisimman hyvin.

Kielten abstraktiuteen liittyen kannattaa muistaa myös kielen taso suhteessa laitteistoon. Esimerkiksi C ja C++ likimain pakottavat kehittäjän ottamaan kantaa muistinhallintaan. Tämä voi olla hyvä asia, mikäli muistia ja sen käyttöä halutaan hallita tarkasti. Toisaalta esimerkiksi Java ja mielestäni vielä abstraktimpi, jopa pseudokoodimainen Python, huolehtivat muistista kehittäjän puolesta. Pythonin heikkoutena voidaan pitää sen hitautta, mutta toisaalta nopeutta vaativia ohjelmiston osia voidaan toteuttaa C:tä käyttäen. Ei ole siis välttämättä järkevää rajoittua ainoastaan yhden kielen käyttöön.

On huomattava, että myös perinteiselle ohjelmointikielelle voidaan antaa graafinen esitys. Ohjelmistojen visualisointiin perehtyvä tutkimus pyrkii nimenomaan tähän. Uskon, että tekstimuotoisen esityksen lisäksi graafiset tavat esittää asioita helpottavat kehitystyötä. Parhaimmillaan järjestelmästä on tarjolla monen eri tason näkymiä. Tämä tosin menee jo ohjelmistoarkkitehtuurien puolelle. :)

Se, kuinka ohjelmointikieli voidaan määritellä, on oleellinen kysymys. Eräs perinteinen määritelmä tälle on se, että kieli on ohjelmointikieli, jos sillä itsellään voidaan kirjoittaa kääntäjä/tulkki kielelle itselleen. Esimerkiksi PyPy toteuttaa Pythonin kielellä itsellään. Määritelmänä tämä ei kuitenkaan ole täysin kattava. Esimerkiksi tätä kriteeriä käyttäen suomenkieli on ohjelmointikieli, koska sen kielioppi voidaan määritellä kielellä itsellään, vai onko? Mikä onkaan perinteisen kielen (suomi, englanti, ym.) ja ohjelmointikielen välinen ero?

Perinteisillä kielillä voi ohjelmoida. Ei tosin tietokoneita. Vaan esimerkiksi tämän tekstin lukijaa. Se mitä kirjoitan saattaa vaikuttaa tai olla vaikuttamatta lukijaan. Ohjelmoinnissa on siis oleellisesti kyse vaikuttamisesta. Kuitenkin koska kyseessä on tietotekniikan kurssi rajaan ohjelmoinnin tarkoittamaan tässä yhteydessä nimenomaan tietokoneiden ohjelmointia vaikka käsitettä sinänsä voisi laajentaa vaikka kuinka.

Perinteisten kielten ja ohjelmointikielten väliseen eroon päästään käsiksi ottamalla huomioon konteksti, jossa niitä käytetään. Perinteistä kieltä käyttäen ei voida ohjelmoida tietokoneohjelmia, ainakaan kovin menestyksekkäästi.

Perinteisten kielten kielioppi voidaan tavallisesti määritellä formaalisti, kuitenkin ottaen mahdolliset poikkeukset huomioon! Tästä syntyykin perinteisten ja ohjelmointikielten merkittävin ero. Ohjelmointikielet ovat täysin formaaleja. Niiden täytyy olla, jotta niitä voidaan käyttää tietokoneen kannalta yksiselitteiseen kommunikointiin.

Mikäli palaa aiemmin esitettyyn ohjelmointikielen alkeelliseen määritelmään (ohjelmointikielellä voidaan ohjelmoida kielen itsensä kääntäjä/tulkki) voidaan havaita, että määritelmää voisi laajentaa myös siten, että kielellä tulisi voida kirjoittaa kääntäjiä/tulkkeja muille kielille. Toisaalta voidaan kirjoittaa ohjelmia, jotka kirjoittavat koodia joko samalla tai toisella kielellä. Tätä tapaa ohjelmoida sanotaan generatiiviseksi. Kyseinen ohjelmointitapa voi olla parhaimmillaan varsin tehokas. Esimerkiksi ohjelmiston tarjoama ohjelmointirajapinta voidaan generoida automaattisesti halutulle kielelle. Eräs mielenkiintoinen sovellus generatiiviselle ohjelmoinnille on tietääkseni erityisten DSL-kielten toteuttaminen.

DSL (Domain Specific Language) pyrkii kuvaamaan kielen ongelmakentän sanastoa käyttäen. Tämä sinällään antaa ylimääräisen abstraktiokerroksen, joka saattaa helpottaa kehitystyötä. On kuitenkin tärkeää muistaa, että mikään abstraktio ei ole täydellinen. Abstraktio on aina enemmän tai vähemmän tarkka approksimaatio kohteestaan. Se voi näyttää erilaiselta tutkailukannasta riippuen. Joten pahimmillaan DSL voi jopa vaikeuttaa asioita, mutta optimistina uskon, että niistä on enemmän hyötyä kuin haittaa, kunhan tietää mitä tekee. :)

Jos kaikista maailman ohjelmointikielistä haluaa löytää edellä mainittujen seikkojen lisäksi yhteisiä piirteitä, käytetään niissä kaikissa symboleja. Symboli on olennainen osa ohjelmointikieltä tai kieltä yleisemminkin, jota ilman ei yksinkertaisesti voi kommunikoida. Toki symbolin puute sinänsä voi olla jo symboli (hyvä esimerkki tästä on välilyönti).

Ohjelmointikielten historia ja niiden kehittyminen aikojen kuluessa kuvastavat hyvin kunkin ajan henkeä. Aluksi ohjelmointikielet olivat, luonnollisesti, hyvin lähellä ns. rautatasoa. Kielet kehittyivät, kuten aiemmin jo viittasinkin kielten käyttötarkoitukseen, tiettyä käyttötarkoitusta varten. Kenties hieman yllättäen useat vanhoina pidetyt kielet ovat yhä hengissä. Kielen ikä ei siis välttämättä tarkoita sitä, että kieli olisi jotenkin huono. Joku voisi jopa väittää, että kieli paranee vanhetessaan, kuten viini ikään. Mielestäni kielen menestymisen kannalta on kuitenkin oleellista, että kieltä kehitetään aktiivisesti eikä sen anneta rämehtyä. Sama pätee myös sovelluksiin.

Se, miten kieltä tulisi kehittää, on hyvä kysymys. Mielestäni on olennaista, että kieltä ei päästetä paisumaan liiaksi vaan se pidetään lähellä varsinaista käyttötarkoitustaan. Esimerkiksi Lua on jossain määrin menestyksekkäästi onnistunut tässä. Pythonin tapauksessa uusimman version 3.0:n tapauksessa kieltä siivottiin ja taaksepäinyhteensopivuus rikottiin. Toisaalta uuteen versioon siirtymistä helpotettiin huomattavasti antamalla kehittäjien käyttöön työkalut sitä varten. Toisaalta myös vanhaa 2.x -sarjaa tuetaan yhä.

Tämän hetken trendeistä vahvin on lienee rinnakkaisuus ja sen tuomat vaatimukset ohjelmoijille sekä ohjelmointikielille. Koska en ole juurikaan perehtynyt rinnakkaisohjelmointiin, olen hieman jäävi kommentoimaan asiaa. Kuitenkin uskoisin, että ajan kuluessa saatavilla olevat työkalut paranevat. Toisaalta myös käsittääkseni luonnostaan hyvin rinnakkaisuutta tukeva ohjelmointiparadigma, funktio-ohjelmointi voi saavuttaa lisää suosiota.

Toisaalta uskon, että useita ohjelmointiparadigmoja tukevat kielet tulevat yleistymään tai ainakin lisäämään suosiotaan. Ohjelmointiparadigman käsite sinänsä on hieman ongelmallinen. Kun esimerkiksi sanotaan, että jokin kieli on oliokieli, mitä se todellisuudessa tarkoittaakaan. :) Kielten, ja erityisesti moniparadigmakielten, jaottelu on vähintäänkin haastavaa.

Steve McConnell puhuu kielessä ohjelmoinnin ja kieleen ohjelmoinnin käsitteistä. Hänen olennaisin sanomansa tässä yhteydessä on nähdäkseni se, että ohjelmoijan ei tulisi rajoittua käyttämään ohjelmointikielen tarjoamia keinoja vaan pyrkiä pikemminkin soveltavaan ratkaisuja, jotka tulevat kielen ulkopuolelta ja ovat tarpeen mukaisia. Tämä ajatus osaltaan auttaa ymmärtämään suhtautumistani ohjelmointiparadigmoihin sekä -kieliin. Osa ohjelmoijan ammattitaitoa on oikean työkalun ja tekniikan hyödyntäminen oikeassa paikassa olemassa olevien rajoitteiden (esim. työpaikan käyttämät teknologiat) puitteissa.

Yhteenvetona totean, että mielestäni tämän "päiväkirjoittelun" myötä pääsin jossain määrin vauhtiin. Voi olla, että myöhemmissä pohdiskeluissa palaan vielä ohjelmointikielen määritelmän pariin. Aiheessa riittää kaluamista vielä.

1 kommentti:

  1. Näköjään todellakin ollut vauhti päällä, kuten yhteenvedossa todettiin. :) Seuraavana nykyisiä, tiivistettyjä mietteitä:

    Ohjelmointikieliä tarkastellessa on oleellista pitää mielessä ainakin käyttötarkoitus, kohderyhmä sekä perimä.

    Kukin kieli jossain määrin räätälöidään tiettyä käyttötarkoitusta varten. Kieli voidaan myös suunnitella siten, että se sisältää näitä räätälöintiominaisuuksia itse (metaominaisuudet). Käyttötarkoituksen mielessä pitäminen on siinä mielessä oleellista, että se auttaa pitämään kielen semantiikan selkeänä. Toisaalta semantiikkaa voi kehittää sopivan laajassa kielessä itse edelleen (vrt. aliohjelmat, luokat, tietueet ym. kielen ryhmittelevät konstruktiot).

    Kohderyhmän käsite on siinä mielessä oleellinen, että kaikkia kieliä ei todellakaan ole tarkoitettu kaikkien käytettäväksi. On tehokkaampaa rajoittaa kielen käyttäjien joukkoa ja pyrkiä tuottamaan heidän kannaltaan paras mahdollinen kieli. Ääritapauksessa käyttäjäryhmä voi olla ainoastaan kehittäjä itse. Kohderyhmä on myös siksi merkittävä, että se auttaa erottelemaan selvästi akateemiset, kokeelliset kielet sekä ns. mainstream kielet toisistaan (siis karkeasti ajatellen. onhan noita kielikategorioita muitakin).

    Kielen perimän käsite on oleellinen, koska se auttaa ymmärtämään sitä miksi kieli on sellainen kuin se on. Ei ole puhdasta sattumaa, että nykykielet näyttävät sellaiselta kuin nyt näyttävät. Nähdäkseni kielten evoluutiossa vallitsee jonkinmoinen kilpailutilanne, jossa heikommat kielet karsiutuvat pois ja vahvimmat jäävät käyttöön. Tämä ei tarkoita etteivätkö heikommat kielet sisältäisi hyödyllisiä ominaisuuksia (vrt. C ja sen viitearitmetiikan aiheuttamat lukuiset bugit).

    VastaaPoista