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 List
nek, 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 aPoint
osztály közvetlen őse lesz azAnyRef
osztály, és közvetlenül alá kerül aNull
osztály. (AList
és azOption
nem bírnak különleges szereppel a többi ,,beépített'' Scala osztályhoz képest: ugyanígyNull
ésAnyRef
közt van aMap
,Set
és a többiek is. Persze ha aPoint
osztály extendeli aShape
traitet mondjuk, akkor az lesz fölötte, és aShape
fölött lesz azAnyRef
.) - A képen láthatjuk, hogy a
Nothing
osztá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 Int
bő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 struct
ok 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 Unit
ot, 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 Unit
hoz,
ez is egy olyan osztály, melynek csak egy lehetséges értéke van) a null
. Idiomatikus Scalában nem
használunk null
t, ahol lehet egy objektumreferencia akár null
is, azt Option
nal 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 null
nak 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 String
et vissza, azzal, hogy lehessen null
is hibajelzésként,
akkor deklarálhatjuk a metódusunkat String
kimenetűnek, és kiértékelődhet null
ra 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?