Ohjelmoinnin perusteet - tehtävän 2 arvostelu
Syksy 2004, kurssikoe
Arvostelija: Vesa Vainio, vesa.vainio@helsinki.fi
Koekysymys:
- "Mitä ihmettä nuo metodit oikein ovat?",
parahtaa ystäväsi kuunnellessaan tarinoitasi Ohjelmoinnin perusteet
-kurssilta. Ystäväsi on ohjelmoinut sen verran, että hän tuntee
yksinkertaiset muuttujat, lausekkeet ja lauseet. "Mitä peijakkaan 'parametreja',
kuka 'kutsuu' ja ketä, miksi?, hän jatkaa toivottomana. Auta
ystävääsi ymmärtämään, mistä oikein on kysymys. Laadi siis asiasta
kirjallinen selitys (enimmäispituus 1 konseptiarkki). Muista että
esimerkit auttavat oppimisessa. Vastauksen arvioinnissa otetaan huomioon
selostuksen ajateltu lukija. Älä siis kirjoita tarkastajalle, joka jo
tuntee asian, kirjoita tuolle ystävälle!
(16 pistettä)
Asteikko: arvostelussa käytettiin asteikkoa, jossa mahdolliset pistemäärät olivat
16, 13, 10, 7, 4 ja 0.
Tehtävä arvosteltiin kokonaisuutena, eli arvosana muodostuu ennen kaikkea
siitä, miten selkeää ymmärrystä metodien toiminnasta vastaus
kokonaisuudessaan ilmentää. Tarkoitus ei siis ollut ladella ulkoa opeteltuja
lauseita, vaan osoittaa selkeää ja johdonmukaista ymmärrystä perusasioista.
Olennaisia asioita olivat:
- Kuvaus siitä, miksi metodien käyttö ohjelmoinnissa on mielekästä.
Tämä löytyi melko "standardimuotoisena" rimpsuna useimmista
vastauksista.
- Kuvaus ja/tai esimerkki siitä, miten metodi määritellään, mukaan lukien
näkyvyys, palautusarvo, nimi ja parametrit. Kelpasi joko kerralla koodissa tai
yksi sana tai määre kerrallaan tekstimuodossa.
- Kuvaus ja/tai esimerkki siitä, miten metodia kutsutaan eli käytetään.
- Kuvaus ja/tai esimerkki siitä, miten arvo palautetaan metodista
(palautusarvon tyypin määrittäminen; return-lause).
- Kuvaus ja/tai esimerkki siitä, miten palautettua arvoa käytetään,
esim.
sijoitetaan muuttujaan, tulostetaan, tai käytetään ehtolauseen ehdossa.
Tämä oli vastauksista useimmin puuttuva kohta.
- Parametrien osalta piti löytyä tieto siitä, että metodi saa
käyttöönsä kopiot todellisten parametrien arvoista, mistä seuraa se,
että metodi ei pysty
parametriensa arvoja muuttamalla saamaan aikaan muutoksia itsensä ulkopuolelle.
Riitti kertoa joko syy tai seuraus, edes jossain muodossa. Kelpuutettiin
myös selkeä maininta siitä, että metodin suorituksen jälkeen parametrit
ja paikalliset muuttujat häviävät.
- Edes vähän jotain olio-ohjelmointiin liittyvää, esimerkiksi
näkyvyysmääreiden (public, private) käsittelyä, kuvausta aksessoreista
ja/tai konstruktoreista, luokka-/oliokohtaisuudesta, tms.
Yllä luetellut pääasiat selkeästi esittämällä sai täydet pisteet.
Muita asioita, jotka katsottin eduksi rajatapauksen ratkaisussa tai
kompensoimassa esitettyjä virheitä:
- Kuvaus metodien kuormittamisesta.
- Kuvaus siitä, että metodin paikallisille muuttujille (mukaan lukien
parametrit) varataan tila metodia kutsuttaessa, ja metodin suorituksen
päätyttyä tämä tila vapautetaan.
- Metodia kutsuttaessa suoritus siirtyy/hyppää metodiin ja suorituksen
jälkeen jatkuu suoritusjärjestyksen mukaan metodikutsua seuraavasta
kohdasta.
- Pääohjelma on metodi.
- Jne.
Esimerkit saattoivat olla koodia tai sanallisia kuvauksia, joko teknisiä tai
vertauskuvallisia. Käytännössä esiintyi hyvin laaja kirjo erityyppisiä
esimerkkejä, joista eduksi katsottiin kaikki muut paitsi sellaiset, jotka
selvästi osoittivat virheellistä tai puutteellista ymmärrystä.
Seuraavassa vielä yleisiä virhekäsityksiä ja niiden korjauksia, sekä
muuta pohdintaa.
Nämä asiat menevät enimmäkseen Ohjelmoinnin perusteet -kurssin asioiden
ulkopuolelle, eivätkä vaikuttaneet
arvosteluun. Korjattakoon ja pohdiskeltakoon hyödyksi kiinnostuneille. Nämä
pohdinnat pitää ymmärtää siten, että mitä kirjoittajan mielestä jatkossa
kannattaa ymmärtää, ei missään tapauksessa niin, että mitä kurssilla
olisi jo pitänyt ymmärtää. Asiat
esitetään jonkinlaisessa subjektiivisessa tärkeysjärjestyksessä:
- Metodeita kutsutaan metodeista, ja pääohjelma on metodi. Ainoa
tapa millä pääohjelma eroaa mistään muusta metodista on se, että
pääohjelman nimen perusteella Javan suoritusympäristö osaa aloittaa
ohjelman suorituksen juuri siitä metodista, eikä jostain toisesta.
Java-kielen kannalta pääohjelmalla ei siis ole mitään muuta
erikoisasemaa muihin metodeihin nähden.
- Hyvin yleisesti metodien käytölle esitettiin perusteluna, että siten usein
toistettavien asioiden ohjelmoiminen helpottuu. Tämä on toki aivan
totta. Tämän lisäksi metodien käytölle on toinen, mahdollisesti
vieläkin tärkeämpi syy, joka liittyy ihmisen ajattelukyvyn rajoituksiin:
Ihminen pystyy kerrallaan pitämään mielessään vain muutaman erillisen
asian, joilla hän voi operoida. Lukumäärän suuruusluokka on noin 4-7 eri
asiaa. (Ohjelmoijan kokemuksesta ja taitotasosta riippuu, miten iso yksikkö
koodista lasketaan "eri asiaksi".) Tästä seuraa, että jos
kirjoitamme pitkiä metodeja, emme pysty kerralla ymmärtämään koko
metodin toimintaa. Tälloin metodin toiminnan hahmottaminen on työlästä
ja virhealtista. Sen sijaan voimme kirjoittaa pieniä ja selkeitä metodeja,
ja koostaa monimutkaisemmat toiminnot, tai pitkät toimintoketjut
tällaisista pienistä ja selkeistä metodeista. Näin voimme kutakin
yksittäistä metodia tarkastellessamme ymmärtää sen toiminnan kerralla
kokonaan. Metodit ovat tällaiseen "eristämiseen" erittäin
sopiva väline juuri siksi, että metodin toimintaan ei voi vaikuttaa
ulkopuoliset asiat; metodin toiminnan voi ymmärtää kokonaan, kun
ymmärtää sen parametrien, paikallisten muuttujien, ja kaikkien lauseiden
merkityksen. Tämän vuoksi metodien käyttö on erittäin hyvä ajatus riippumatta
siitä, tehdäänkö jokin asia ohjelmassa useita kertoja vai vain yhden
kerran. Siis: metodeja voi ja kannattaa käyttää monimutkaisen toiminnon
pilkkomiseen osiin, vaikka siitä seuraisikin metodeja, joita kutsutaan vain
yhdestä paikasta. Tosin metodien käyttö tähän tarkoitukseen taitaa ensinnäkin
edellyttää kohtalaisen hyvää ymmärrystä metodien toiminnasta (mikä
ilmeisesti opetetaan ihan kunnolla vasta Java-ohjelmointi-kurssin
loppuvaiheessa). Toisekseen toimintojen eristäminen omiin siisteihin
metodeihin on taito sinänsä, mikä pitää erikseen oppia. Kannattaa
kuitenkin opetella.
- Sekä määreestä private että määreestä static
sanottiin, että se tarkoittaa "luokkakohtaista". Mistä mahtaa
olla kysymys? Private on näkyvyytensä puolesta luokkakohtainen, eli
private-jäseneen pääsee käsiksi vain samasta (siitä, jossa jäsen on
määritelty) luokasta, ei muista luokista. Jonkin luokan static-jäsen taas
on luokkakohtainen siinä mielessä, että luokan static-jäsen on olemassa
ja käytettävissä myös silloin, kun luokasta ei ole luotu yhtään
ilmentymää eli oliota. Static-jäsenen vastakohta on oliokohtainen jäsen,
eli jonkin yhden tietyn olion jäsen. Oliokohtaisessa tähän "yhteen
tiettyyn" olioon voi viitata käyttämällä viitettä this, kun
taas static metodissa ei ole lainkaan mahdollista käyttää viitettä this.
(Olioiden ja luokkien jäsenet taas ovat sekä niiden muuttujat että
niiden metodit.)
- Melko yleisesti joko palautusarvon tai parametrien tyypistä
puhuttaessa lueteltiin esimerkiksi joitakin tyyppejä (int, double, boolean,
String). Monesti tässä yhteydessä käytetystä kielenkäytöstä kuvastui
melko sekava ymmärrys tyypin käsitteestä. Siis: missä tahansa,
missä määritellään jonkin asian tyyppi (muuttujan, metodin
palautusarvon tai metodin parametrin), kelpaa määrittelyksi mikä tahansa
Javan tyyppi. Tyypit taas ovat joko alkeistyyppejä tai oliotyyppejä. Olioita
käytettäessä ei ole mitään eroa sillä, sattuuko tyypin
määrittely (eli luokka) sisältymään Java-kielen valmiisiin luokkiin,
vai onko se käyttäjän "oma". Tyyppi kuin tyyppi. Ja String on
oliotyyppi, ei alkeistyyppi. Javan valmiissa kalustossa kaikki mikä kirjoitetaan isolla
alkukirjaimella, on aina luokan nimi, eli oliotyyppi (mukaan ei lasketa
"vakioita", joiden nimet kirjoitetaan kokonaan isolla).
Alkeistyyppien nimet kirjoitetaan aina pienellä. Tästä syystä on tapana
nimetä luokat siten, että nimi alkaa isolla alkukirjaimella. Jos tätä
tapaa noudattaa omien luokkien nimeämisessä, koodin tyyli säilyy
yhtenäisenä, ja myös omien luokkien kohdalla tyypin eli luokan nimen voi
erottaa muuttujan tai metodin nimestä jo alkukirjaimesta.
- Hyvin yleisesti esitettiin käsitys,
että metodin suorituksen loppuessa roskienkerääjä käy vapauttamassa metodin paikallisilta muuttujilta vapautuneen muistin. Tämä ei pidä
paikkaansa. Roskienkerääjä syö vain kokonaisia olioita. Metodien paikallisille
muuttujille varataan tila eri paikasta ja eri tavalla kuin olioille. (Tosin jos
metodissa luodaan uusia olioita, eikä viitettä niihin tallenneta muualle
kuin metodin paikallisiin muuttujiin, niin silloin metodissa luodut oliot
jäävät roskienkerääjän ruuaksi. Näin asiaa ei kuitenkaan taidettu
ilmaista yhdessäkään paperissa. Tällöinkin roskienkerääjä syö vain
oliot, ei niitä metodin paikallisia muuttujia.)
- Saattaa olla myös hyödyllistä ymmärtää, että sekä näkyvyyden
tarkistaminen että luokka-/oliokohtaisuuteen liittyvät tarkistukset tekee kääntäjä
(komento javac) silloin kun ohjelma käännetään. Siksi on oikeastaan
väärin sanoa, että jos näkyvyysmääreistä kuvattuja sääntöjä rikotaan, niin
"ohjelma ilmoittaa virheestä". Ohjelma ei voi ilmoittaa
virheestä, koska virheellistä ohjelmaa ei pysty kääntämään, eikä
siksi koskaan edes käynnistämään (komento java). Samaten monet
tyyppeihin liittyvät tarkistukset tekee jo kääntäjä, niitäkään ei
siis tehdä ohjelman suorituksen aikana.
Vesa Vainio, 21.11.2004