i'm reading functional programming in scala, , in chapter 04 authors implement option on own. now, when defining function getorelse
use upper bound restrict type of a
supertype (if understood correctly)
so, definition goes:
sealed trait option[+a] { def getorelse[b >: a](default: => b): b = match { case none => default case some(a) => } }
so, when have
val = some(4) println(a.getorelse(none)) => println prints integer value val b = none println(b.getorelse(some(3)) => println prints option[integer] value
a
has type option[int]
, a
type int
. b
type nothing
. nothing
subtype of every other type. means option[nothing]
subtype of option[int]
(because of covariance), right?
but b >: a
said b
has supertype?! how can int
back? bit confusing me...
anyone care try , clarify?
that means option[nothing] subtype of option[int] (because of covariance), right?
correct. option[nothing]
option[int]
.
but b >: said b has supertype?! how can int back?
it doesn't have super-type. requires a
lower-bound. means can still pass int
getorelse
if a
int
.
but doesn't mean can't pass instances of sub-class. instance:
class class b extends class c extends b scala> option(new b) res196: option[b] = some(b@661f82ac) scala> res196.getorelse(new c) res197: b = b@661f82ac scala> res196.getorelse(new a) res198: = b@661f82ac scala> res196.getorelse("...") res199: object = b@661f82ac
i can still pass instance of c
, because c
can up-cast b
. can pass type higher inheritance tree, , getorelse
return type, instead. if pass type has nothing type contained in option
, type least upper-bound inferred. in above case, it's any
.
so why lower-bound there @ all? why not have:
def getorelse[b <: a](default: => b): b
this won't work because getorelse
must either return a
that's contained in option
, or default b
. if return a
, , a
not b
, type-bound invalid. perhaps if getorelse
returned a
:
def getorelse[b <: a](default: => b):
this work (if defined way), restricted type-bounds. in above example, pass b
or c
getorelse
on option[b]
. in case, not how in standard library.
the standard library getorelse
allows pass it. have option[a]
. if pass sub-type of a
, up-cast a
. if pass a
, okay. , if pass other type, compiler infers least upper-bound between two. in cases, type-bound b >: a
met.
because getorelse
allows pass it, many consider tricky. example have:
val number = "blah" // ... lots of code val result = option(1).getorelse(number)
and compile. we'll have option[any]
cause error somewhere else down line.