Ohjelmointitekniikka (Scala), kevät 2012

Kurssikoe 28.02.2012, arvosteluperusteet
Heikki Korhola (etunimi.sukunimi ät cs.helsinki.fi)


Kokeessa edellytettiin kohtuullisen syvällistä tuntemusta (kaikki vaadittava löytyy luentomateriaalista) nimenomaan Scalan erikoisuuksista. Javan ja Scalan syntaktiset erot ovat vain pieni osa kokonaisuutta. Allaolevissa tehtäväkohtaisissa perusteissa esiintyviä käsitteitä ei tarvinnut välttämättä mainita nimeltä, jos oleellinen kävi vastauksessa ilmi. Aiheen viereestä tarinointi on vain yksittäisten irtopisteiden arvoista, vaikka siinä olisikin oikeaa asiaa. Konsepteille piirretyt sarjakuvat tai biitsillä löhöävät tikku-ukot olivat 0,4 pisteen arvoisia (pyöristys normaalisti).


1. Selitä lyhyesti mutta täsmällisesti:

(15 p)

Huolellinen kannatti olla. Täydet pisteet kustakin kohdasta saa vain kattavalla ja täsmällisellä selityksellä (ei terminologian väärinkäyttöä!), kuten tehtävänantokin antaa ymmärtää.

a. pääkonstruktori ja sen parametrien merkitys (3p)

  • luokkamäärittelyn yhteydessä (1p)
  • parametreistä tulee luokan kenttiä (1p)
  • näkyvyysmääreet, val/var (1p)
    Ilman eri määreitä pääkonstruktorin parametreistä tulee olioprivaatteja vakiokenttiä (private[this] val)!

b. oliokumppani (companion object) ja sen tyypillinen käyttö (3p)

  • kumppaninsa (luokka, trait) niminen ainokainen (2p)
  • tehdasmetodit (1p)
  • "Javan static", kirjastojen toteutus, luokka- ja ilmentymäkohtaisten tietojen erottelu (1p)

c. paikanpitäjäparametri (placeholder) (3p)

  • mahdollistaa funktioliteraalien kirjoittamisen tiiviimpään muotoon (2p)
  • merkitään _-merkillä (1p)
  • parametri voidaan jättää nimeämättä (1p)
  • parametri voidaan jättää tyyppipäättelyn ansiosta tyypittämättä (1p)
    Huom. paikanpitäjäparametri esiintyy vain funktioliteraalien yhteydessä! Tavallisessa funktiomäärittelyssä (def) sitä ei voida käyttää. Myös osittain sovellettujen funktioiden yhteydessä kysymys on funktioliteraaleista. Ks. Osittain sovelletut funktiot.
    Importin yhteydessä _ ei ole parametri. (±0p)

d. määre abstract override (3p)

  • esiintyy pinoutuvien muunnosten yhteydessä (1p)
  • esiintyy alitraittien yhteydessä (1p)
  • vaaditaan abstraktin metodikutsun (sitomaton super) takia (2p)
    Kysymys on siitä, että luotaessa ilmentymää koostamalla, jostakin kohtaa hierarkiaa on löydyttävä super-viittauksen kautta kutsuttavalle metodille konkreettinen toteutus (jotta mahdolliset ongelmat havaittaisiin jo käännösaikana). Määreellä abstract override merkitty metodi ei itse ole abstrakti metodi!

e. vapaa ja sidottu muuttuja (3p)

  • funktioliteraaleihin ja sulkeumiin liittyviä käsitteitä (1p)
  • sidottuja ovat funktion määrittelyssä merkityksensä saavat tunnukset (1p)
  • vapaita ovat tunnukset, jotka esiintyvät literaalin ulkopuolella (1p)
  • vapaat muuttujat sidotaan, eli suljetaan sulkeuman sisään suoritusaikana (1p)
    Sulkeuma on (vapaita muuttujia sisältävän) funktioliteraalin ilmentymä, joka määrittyy käännösaikana mutta luodaan suoritusaikana.

2. Mitä ovat ohuet (thin) ja rikkaat (rich) rajapinnat? Millä tavoin piirreluokat liittyvät asiaan? Anna esimerkkejä ohjalmahahmotelmina ja käytä selityksen esimerkkeinä myös piirreluokkia Ordered, Iterable ja Iterator.

(10p)

  • paljon (rikas) vai vähän (köyhä) operaatioita (3p)
  • toteuttamalla köyhä, saadaan rikas (3p)
  • tekniikka ei olisi mahdollinen, jos piirreluokat eivät saisi sisältää koodia (2p)
  • esimerkki (Ordered, Iterable ja Iterator) (2p)

Rajapinnalla tarkoitetaan käytettävissä olevien operaatioiden joukkoa. Se on eri asia kuin rajapintaluokka (jollaisia Scalassa ei ole).


3. Mitä seuraava tulostaa:

val lista = for (i <- 1 to 5; j <- i to 5; if (i+j)%2 == 0) yield(i+j)
lista.foreach(println)
Miksi? Miten kaikki oikein käy? Mistä tekniikasta ensimmäisellä rivillä on kysymys? Selitä tämä tekniikka ja sen käyttö. Pelkästä tulostuksesta ei saa pisteitä, mutta myös ilman oikeaa tulostusta pisteet ovat tiukassa.

(10p)

Oikea tulostus: 2, 4, 6, 4, 6, 6, 8, 8, 10.

  • tulostus oikein (4p)
  • kaksi arvoväligeneraattoria (2p)
  • suodatin (2p)
  • yield (2p)
irtopisteitä:
  • funktioparametri (1p)
  • osittain sovellettu println (1p)
  • tyyppipäättely, ... (1p)
    Huom. "sisäkkäiset luupit"-tyyppinen vastaus on hieman epätäsmällinen. Useamman generaattorin ketjuttaminen forin otsakkeessa sinänsä vastaa esimerkiksi Javan sisäkkäisiä for-lauseita iteroinnin puolesta, mutta for-yield -rakenteessa (listakomprehensio) on kysymys arvojonon tuottamisesta. Oikeastaan yield-määre ilmaisee vain, että iteraation tulokset jäävät (komprehension palautusarvona) talteen, kun taas tavanomainen for-lause palauttaa Unit-tyyppisen arvon.


4. Mitä seuraava tulostaa:

val l = List(9,8,7,6,5)
val m = Array(5,4,3,2,1)
var b = 0
l.foreach(x => {m(b)*=x; b+=1})
m.foreach(println)
Miksi? Miten kaikki oikein käy? Mistä tekniikasta on kysymys neljännellä rivillä? Selitä tämä tekniikka ja sen käyttö. Pelkästä tulostuksesta ei saa pisteitä, mutta myös ilman oikeaa tulostusta pisteet ovat tiukassa.

(10p)

Huom. tehtävänannossa kiinnitettiin erityishuomiota neljänteen riviin. Yllättävän monen mielestä funktion välittäminen parametrinä toiselle funktiolle ei ollut tässä mitenkään huomionarvoista, puhumattakaan siitä että kyseessä on sulkeuma.

Oikea tulostus: 45, 32, 21, 12, 5.

  • tulostus oikein (4p)
  • funktioparametri (2p)
  • 4-rivin funktion kuvaus (1p)
  • sulkeuma kattavasti selostettuna (3p)
irtopisteitä:
  • osittain sovellettu println (1p)
  • tehdasmetodi, tyyppipäättely, val/var, taulukon indeksi kaarisuluissa, ... (1p)

(Ei vaikuta arvosteluun:) Neljännellä rivillä foreach:lle annettu funktio ei muokkaa sen kummemmin listaa l itsessään (se on vakio) kuin sen alkioitakaan (nekin ovat immutaabelissa listassa vakioita!). Literaalin oikea puoli on Unit-tyyppinen funktio.