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.