Oppimateriaalin copyright © 2009 Arto Wikla. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.
(Muutettu viimeksi 3.4.2009)

Immutaabeli olio

Javan String-olioiden muuttumattomuus oli ehkä tulevaisuutta ennakoiva (eli avantgardistinen) idea?

Ajatuksena on, että kerran luotua olioarvoa ei voi koskaan muuttaa, jolloin mitään rinnakkaisten säikeiden poissulkemista tällaisten olioiden käpälöinnissä ei tarvitse harrastaa. Ja näin osa rinnakkaisohjelmoinnin ongelmista poistuu. Roskaa syntyy, totta kai, mutta Java-toteutusten myötä roskankeruun tekniikka on kehittynyt huimasti. Ja säikeitähän riittää hoitelemaan siivoushommiakin...

Ehkäpä vielä koittaa "funktionaalisen olio-ohjelmoinnin" aika?

Seuraavassa rationaalilukujen toteutus "immutaabelina" oliona:

class Rational(n: Int, d: Int) {

  private def gcd(x: Int, y: Int): Int = {
    if (x == 0) y
    else if (x < 0) gcd(-x, y)
    else if (y < 0) gcd(x, -y)
    else gcd(y % x, x)
  }

  private val g = gcd(n, d)

  val numer: Int = n/g
  val denom: Int = d/g

  def +(that: Rational) =
    new Rational(numer * that.denom + that.numer * denom, denom * that.denom)

  def -(that: Rational) =
    new Rational(numer * that.denom - that.numer * denom, denom * that.denom)

  def *(that: Rational) =
    new Rational(numer * that.numer, denom * that.denom)

  def /(that: Rational) =
    new Rational(numer * that.denom, denom * that.numer)

  override def toString() = "(" + numer + "/" + denom +")"
}

Luokan käyttöä perinneohjelmoinnissa:
println("Rationaalilaskentaa.")
println("Anna ensimmäisen luvun osoittaja ja nimittäjä.")
val a = new Rational(readInt, readInt)
println("Anna toisen luvun osoittaja ja nimittäjä.")
val b = new Rational(readInt, readInt)

println("Lukujen " + a + " ja " + b +" summa, erotus, tulo ja osamäärä ovat:")
println(a+b)
println(a-b)
println(a*b)
println(a/b)
Ohjelman suoritusesimerkki:
Rationaalilaskentaa.
Anna ensimmäisen luvun osoittaja ja nimittäjä.
4
9
Anna toisen luvun osoittaja ja nimittäjä.
3
6
Lukujen (4/9) ja (1/2) summa, erotus, tulo ja osamäärä ovat:
(17/18)
(-1/18)
(2/9)
(8/9)

[Hienompi versio rationaalilukujen toteutukseksi]

Harrastetaan sitten vähän "funktionaalista ohjelmointia" - klassisen hirveä toteutus Fibonaccin luvun laskemiseen:

def fibo(i:Int):Int = if (i<2) 1 else fibo(i-1) + fibo(i-2)

println("Kultaisen leikkauksen aproksimointi kahden peräkkäisen Fibonaccin luvun suhteena.")
println("Miten pitkälle edetään?")
val lkm = readInt

println(new Rational(fibo(lkm),fibo(lkm-1))) // ei erityisen tehokasta: O(2n) !! ;-)

println(1.0*fibo(lkm)/fibo(lkm-1)) // vain tarkistukseksi
Suoritusesimerkki:
Kultaisen leikkauksen aproksimointi kahden peräkkäisen Fibonaccin luvun suhteena.
Miten pitkälle edetään?
40
(165580141/102334155)
1.618033988749895



Takaisin sisältösivulle.