Muutettu viimeksi 29.3.2016 / Sivu luotu 14.4.2010 / [oppikirjan esimerkit] / [Scala]
Sivun sisältöä:
final def == (that: Any): Boolean final def != (that: Any): Boolean def equals(that: Any): Boolean def ##: Int def hashCode: Int def toString: StringKuten näkyy, mikään luokka ei voi korvata yhtäsuuruus- ja erisuuruusoperaatiota (final), mutta equals-metodia sitä sitten korvataankin... Oletustoteutus on Javan tapaan oliosamuus.
Operaatiot == ja != kuitenkin tavalla tai toisella johtavat equals-vertailuun ja siten polymorfismin ansiosta niitä voidaan käyttää myös itse ohjelmoidun samuuden vertailuun. Nuo kaksi operaatiota on ohjelmoitu siten, että ne kutsuvat equals-metodia.
Jo kurssin alussa kuultiin se ilosanoma, että esimerkiksi merkkijonojen samuuta Scalassa voi (järkevästi) vertailla operaatioilla == ja !=.
Huom: Kun ohjelmoi omalle luokalleen equals-metodin, on syytä pitää huoli, että toteuttaa ekvivalenssirelaation ja myös että samaistettavien olioiden hashCode on sama, ks. API.
Metodi toString Javan tapaan antaa oletusarvoisen "teknisen" tulostusasun kaikkien luokkien ilmentymille. Tapana on korvata tulostusasu käyttökelpoisemmalla.
Lukuunottamatta viimeistä nuo vastaavat Javan alkeistyyppejä. Myös ohjelman suoritusaikana ne (useimmiten) voidaan toteuttaa alla lymyävän Javan tapaan.
Scalassa myös Javan alkeistyyppien vastineiden ajatellaan olevan olioita. Niitä ei kuitenkaan konstruoida tyyliin new Int(5). Ainoa tapa luoda tällaisia olioita on kirjoittaa ne ohjelmaan literaaleina: 345, 3.14, false. Teknisesti asia on hoideltu määrittelemällä nuo luokat abstrakteiksi ja "finaaleiksi".
Luokalla Unit on vain yksi ilmentymä: (). Se on kaikkien "arvoa palauttamattomien" "funktioiden" arvo...
Koska esimerkiksi siis Int on Anyn aliluokka, se perii Anyn kaluston:
println(4321.toString) // 4321 println(4321.hashCode) // 4321 println(4321.equals (4000+321)) // true
Matematiikasta poiketen "pienet kokonaisluvut" eivät ole "kokonaislukujen" osajoukko (aliluokka), "kokonaisluvut" eivät ole "reaalilukujen" osajoukko (aliluokka), jne. Itse asiassa tietokoneessa näiden tyyppien sisäiset esitykset ovatkin aidosti erilaisia. Tätä heijastellee myös Scalan valinta esittää numeeriset tyypit rinnakkaisina periytymishierarkiassa.
Javasta tutut "sallitut sijoitukset", implisiittiset tyyppimuunnokset, tiettyjen numeeristen tyyppien välillä ovat käytössä myös Scalassa. Kannattaa muuten huomata, että nämä todellakin aiheuttavat töitä myös ohjelman suoritusaikana.
Piirretyypit ("trait") tuovatkin sitten oman lisävärinsä asioihin. Kuvassa näkyy jo yksi tällainen, ScalaObject, jota käytetään joihinkin käännösteknisiin jippoihin...
Kaikkien Scalan luokkien yhteinen aliluokka on sitten se vihoviimeinen Nothing. Se on sikälikin nimensä mukainen, ettei siitä ole olemassa ainuttakaan ilmentymää.
Mihin sellaista voi käyttää? No sitä voi käyttää tyyppinä! Jos vaikkapa funktion tyyppi on Nothing, tuon funktion voi sijoittaa minne tahansa, minne jonkin arvon voi sijoittaa.
Kuten on opittu, Scalassa (melkein) kaikella on arvo. Niin myös throw-ilmauksella:
val n = scala.io.StdIn.readInt val half = if (n % 2 == 0) n / 2 else throw new RuntimeException("n must be even")Mitään arvoahan ei muuttujalle half aseteta, jos n on pariton. Vahvasti tyypitetyssä kielessä "arvoilla" pitää kuitenkin aina olla tyyppi. Teknisesti throw-lause on tyypiltään Nothing, joka on kaikkien Scalan tyyppien alityyppi. Tässä esimerkissä se tarkoittaa, että Nothing kelpaa esim. juuri Int-tyyppiseksi arvoksi!
[Tulipa muuten kokeiltua, vaikka ei ihan tähän liitykään:
Kokeillaan parillisella ja parittomalla:
val n = scala.io.StdIn.readInt
val half =
if (n % 2 == 0)
n / 2
else
println("n must be even")
println(n)
println(half)
Toimii! Lauseen println tyyppi on
Unit ja halfin tyypiksi tulee tässä
AnyVal.
Syötetään 44:
44
22
Syötetään 33:
n must be even
33
()
Tämä syrjähyppy ei kuulu kurssiin.]
Vielä yksi järkevä esimerkki: Scalan standardikirjastossa on metodi
def error(message: String): Nothing = throw new RuntimeException(message)jota voi käyttää tyyliin:
def divide(x: Int, y: Int): Int = if (y != 0) x / y else sys.error("Nollalla ei saa jakaa!") val a = divide(1,0)Seuraus:
java.lang.RuntimeException: nollalla ei saa jakaa at scala.sys.package$.error(package.scala:27) at Main$$anon$1.divide(tmp.sca:4) ... jne...Tässäkin Nothing-tyyppinen funktio kelpaa Int-arvoksi.
(Hmm... Tuon Nothing-luokan tyylikkyydestä voi olla ainakin kahta eri mieltä...)