Helsingin yliopisto / tietojenkäsittelytieteen laitos / Ohjelmointitekniikka (Scala) / © Arto Wikla 2010

2 Pikku perusteita

Muutettu viimeksi 18.3.2010 / Sivu luotu 9.3.2010 / [oppikirjan esimerkit] / [Scala]

Sivun sisältöä:

Tulkissa

$ scala
Welcome to Scala version 2.7.5final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_10).
Type in expressions to have them evaluated.
Type :help for more information.

scala> 1 + 2
res0: Int = 3
scala> res0 * 3
res1: Int = 9
Tulkki siis laittaa nuo arvot itse nimeämiinsä systeemivakioihin res0, res1, res2, ...

scala> println("Hello, world!")
Hello, world!
Metodikutsut ja muut algoritminpalaset suoritetaan sellaisinaan.

scala> val msg = "Hello, world!"
msg: java.lang.String = Hello, world!

scala> val msg2: java.lang.String = "Hello again, world!"
msg2: java.lang.String = Hello again, world!

scala>  println(msg)
Hello, world!
Nimettyjä vakioita voi tietenkin määritellä itsekin. Mutta ne siis ovat vakioita:
scala> msg = "Goodbye cruel world!"
<console>:5: error: reassignment to val
       msg = "Goodbye cruel world!"
           ^
Toki muuttujiakin voi määritellä:
scala> var muu = 666
muu: Int = 666

scala> println(muu)
666

scala> muu = 14
muu: Int = 14

scala> println(muu)
14

Rakenteen jäädessä kesken tulkki antaa uuden rivin:
scala> val multiLine =
     | "This is the next line."
multiLine: java.lang.String = This is the next line.
Tyypillisesti näin käy funktion määrittelyssä:
scala> def max(x: Int, y: Int): Int = {
     | if (x > y) x
     | else y
     | }
max: (Int,Int)Int
Jos funktion runko muodostuu yhdestä lauseesta, aaltosulkeet saa jättää poiskin:
scala> def max2(x: Int, y: Int) = if (x > y) x else y
max2: (Int,Int)Int

scala> max(3, 5)
res5: Int = 5
Näiden kahden funktion tyyppi siis on (Int,Int)--->Int.

Huom: Funktion arvon tyyppi ilmaistaan otsikossa, ellei kääntäjä osaa sitä päätellä. Ja palautettavan arvon ilmaisemiseen riittää algoritmin suorituspolun viimeinen ilmaus, mitään returneja ei tarvita. Toisaalta return-lause on myös käytettävissä, jos halutaan algoritmiin useita erillisiä lopetuskohtia. Tätä ei kuitenkaan Scala-maailmassa pidetä tyylikkäänä eikä suotavana!

Huom: Koska "kaikella on arvo" ja arvo on lause-/lausekejonon viimeinen arvo, seuraavanlainen sivuvaikutuksilla pelleilykin on mahdollista:

scala> val x = {println("böö"); 78}
böö
x: Int = 78

Huom: Funktion muodollisten parametrien tyyppi annetaan aina, vaikka monissa muissa tilanteissa kääntäjä osaa päätellä tyypin.

"Void-metodin" tyyppi on Unit:

scala> def greet() = println("Hello, world!")
greet: ()Unit
Parametrittoman funktion kutsussa tyhjä parametrilista ei ole tarpeen:
scala> greet
Hello, world!

scala> greet()
Hello, world!

scala> exit
$

Komentoriviparametri skriptissä

  // Say hello to the first argument
  println("Hello, "+ args(0) +"!")
Huom: Taulukon indeksit ovat kaarisulkeissa!

Valintaa ja toistoa, funktioita

[oppikirjan esimerkit]

Tuttua ja turvallista:

  var i = 0
  while (i < args.length) {
    println(args(i))
    i += 1
  }
Ja iffitkin peliin:
  var i = 0
  while (i < args.length) {
    if (i != 0)
      print(" ")
    print(args(i))
    i += 1
  }
  println()
Huom: Scalassa ei ole operaatioita ++i ja i++. Ja hyvä niin! Ehtojen ympärillä on Javan tapaan oltava kaarisulkeet.

Skaalautuvalla Scalalla tuommoinen perinneohjelmointi toki onnistuu, ohjelmointi, jossa peräkkäin suoritettavin operaatioin muutetaan ja tutkitaan muuttujien arvoja eli ohjelman tilaa (state).

Mutta Scalalla hommia voi hoidella korkeammallakin abstraktiotasolla, vähän niin kuin funktionaalisemmin. Komentoriviparametrit voi tulostaa vaikka näin:

  args.foreach(arg => println(arg))
Näyttää siistiltä, mutta mitä tässä oikeastaan sanotaan?

Esimerkki: Laaditaan funktio, joka saa parametrina kaksi kokonaislukua ja funktion, joka kuvaa kaksi lukua kolmanneksi. Laadittava funktio soveltaa saamaansa funktiota parametrilukuihin:

  def koristele(x: Int, y: Int, arvo: (Int, Int) => Int) =
    println("**** " + arvo(x, y) + " ****")
Ja näin kätevästi sitä sitten voi käyttää:
  koristele(5, 9, (x: Int, y: Int)  => x + y)  // **** 14 ****
  koristele(5, 9, (x: Int, y: Int)  => x * y)  // **** 45 ****

  def erotus(a: Int, b: Int) = a-b
  koristele(5, 9, erotus)                      // **** -4 ****
Kuten näkyy, todellisena funktioparametrina voidaan antaa funktioliteraalien lisäksi toki myös nimettyjä funktioita.