30 - Any, Anyref, AnyVal, Null és Nothing¶
Most, hogy kovariáns a listánk, végre meg tudjuk oldani azt, hogy ne így kelljen ezt:
1 | |
Nil[Int], egy Nil[Long] stb,
valamilyen típusparaméter kellett a Listnek, amit extendeltünk és ha object, akkor ő maga nem lehet generikus.
De most, hogy kovariáns T-ben a listánk, mire is lenne szükségünk? Arra, hogy a Nil jó legyen List[Long]-nak
is, List[String]-nek is, bárminek. Ez a kovariancia miatt akkor lenne lehetséges, ha lenne egy olyan X típus, ami
minden más típusnak leszármazottja.
Nothing¶
Van ilyen típus! A neve pedig Nothing. Egy jó képet láthatunk a Scala osztályhierarchiájáról
itt.
Mit látunk a képen?
- Scalában mindennek van valamiféle típusa, és valahova ebbe a hierarchiába kerül be.
- Konkrétan ami osztályokat mi implmentálunk, az automatikusan a Null és az AnyRef osztályok közé fog kerülni.
Ha csak annyit írunk, hogy
case class Point(x: Int, y: Int), akkor ennek aPointosztály közvetlen őse lesz azAnyRefosztály, és közvetlenül alá kerül aNullosztály. (AListés azOptionnem bírnak különleges szereppel a többi ,,beépített'' Scala osztályhoz képest: ugyanígyNullésAnyRefközt van aMap,Setés a többiek is. Persze ha aPointosztály extendeli aShapetraitet mondjuk, akkor az lesz fölötte, és aShapefölött lesz azAnyRef.) - A képen láthatjuk, hogy a
Nothingosztály mindennek a leszármazottja lesz automatikusan.
Vajon akkor hogyan tudjuk objektumként deklarálni a Nil-t, ha azt akarjuk, hogy olyan lista legyen, ami bármilyen
listának megfelel?
1 | |
Válasz mutatása
Ezzel már el is értük, hogy a Nil objektum az teljesen jó lesz pl. List[Int]-nek (hiszen Nothing <: Int),
vagy List[String]-nek (hiszen Nothing <: String), vagy List[Pet]-nek, mindennek, mert a listánk kovariáns.
Felmerülhet persze a kérdés, hogy mégis milyen értékek lehetnek Nothing típusúak, nos, a névválasztás nem véletlen,
semmilyenek, nincs olyan objektum, ami Nothing típusú lenne. Ez a típus elsősorban erre való, kovariáns
generikus osztályoknak olyan objektumait definiálni, amik minden típusparaméter mellett megfelelnek az adott
osztály példányainak.
Illetve, már találkoztunk Nothing típusú ,,függvénnyel'', a Predef osztályban deklarált ??? függvénnyel:

Láthatjuk, hogy ez a függvény soha nem ad vissza értéket, csak kivételt dob, ezért valahol validnak hangzik,
hogy a típusa akár Nothing is lehet: mindig igaz, hogy ha kiértékelődik valamire (amit nem fog), akkor az
értéke Nothing típusú lesz. Mindenesetre ezzel elérjük azt, hogy bármilyen típusú még nem implementált
függvényünk (vagy értékünk) van, akkor ideiglenesen fejlesztés közben a ??? függvényt írva oda fordulni
fog a kódunk, mert a Nothing típusú ??? minden típusnak megfelel.
AnyRef, AnyVal, Any¶
Ahogy a képen is látszik, az AnyRef valójában egy alias a java.lang.Object-re, ez mondjuk össze is cseng azzal,
hogy az osztályaink ez alá kerülnek be közvetlen, ha mást nem mondunk, Javában is ez történik. Minden, ami a JVM számára
,,Object'', ide fog kerülni.
Ezzel párhuzamosan van az AnyVal osztály, ami alatt főképp azok a típusok kaptak helyet, melyek nem is objektumra
fordulnak, hanem a legtöbb esetben a Java egy-egy elemi típusára: a Scalás Intből a JVM számára int lesz
(nem Integer), a Double-ből double stb. Ezeket a típusokat value type-nak is hívják, szemben
az objektumok reference type-jával, innen az osztályok neve: ha pl egy metódust írunk, ami kap egy valamilyen
típusú paramétert, akkor ha ez egy reference type, úgy a címe, a referenciája kerül átadásra az objektumnak
(és ha lenne mutátor metódusa, akkor az eredeti objektumot is megváltoztathatnánk vele a függvényben),
ha pedig value type, akkor egy másolat kerül átadásra a függvénynek. (C-ben a structok value typeok,
Javában ilyen nincs.)
Persze ahogy ,,legalsó'', úgy ,,legfelső'' osztályra is szükség van (pl. ha egy List[Pet] elé beszúrunk egy
Int-et, annak is lehessen típusa), kell valaki az AnyVal és az AnyRef közé is, ez az Any osztály, aminek
tényleg minden leszármazottja. (Azért sok esetben ha a fordító az Any típust következteti ki valaminek, kezdhetünk
gyanakodni, hogy valami nem stimmel.)
Unit, Null¶
Az AnyVal osztály alatt találjuk még a Java primitív típusain felül a Unitot, amiről már tudjuk, hogy
egyetlen értéke a (): neki az elsődleges funkciója az, hogy alapvetően a mellékhatás miatt kiértékelt
kifejezéseknek is legyen valamiféle típusuk, Javás környezetben leginkább void lesz belőle.
Egy osztály van még, melyről nem volt szó, a Null: ennek az egyetlen példánya (hasonlóan a Unithoz,
ez is egy olyan osztály, melynek csak egy lehetséges értéke van) a null. Idiomatikus Scalában nem
használunk nullt, ahol lehet egy objektumreferencia akár null is, azt Optionnal illik megoldani,
nem pedig folyamatos null checkekkel, de mivel használhatunk Scalából Java kódot és viszont, Javában
pedig a null egy teljesen bevett szokás, ezért arra, hogy Java oldalról érkezik egy null, fel kell
készülnünk. A nullnak viszont van egy olyan tulajdonsága, hogy bármilyen objektum referencia helyett
használható, ezért került be ez az osztály az összes AnyRef alatti osztály alá: így a null
lehet String is, vagy Integer, esetleg Pet is. (Plusz, ha Java oldalra az az igény, hogy adjunk
pl. Option[String] helyett Stringet vissza, azzal, hogy lehessen null is hibajelzésként,
akkor deklarálhatjuk a metódusunkat String kimenetűnek, és kiértékelődhet nullra is, le fog fordulni,
mert a null megfelel Stringnek is.
Az if-else elmaradó else ága¶
Mi lehet a típusa az if ( 3 < 4 ) "kék" kifejezésnek?