Why Some(null) isn't considered None?

前端 未结 6 1856
感动是毒
感动是毒 2020-12-15 02:38

I am curious:

scala> Some(null) == None
res10: Boolean = false

Why isn\'t Some(null) transformed to None?

相关标签:
6条回答
  • 2020-12-15 03:12

    You should use Option(null) to reach the desired effect and return None.

    Some(null) just creates a new Option with a defined value (hence Some) which is actually null, and there are few valid reasons to ever create one like this in real code.

    0 讨论(0)
  • 2020-12-15 03:13

    Unfortunately, null is a valid value for any AnyRef type -- a consequence of Scala's interoperability with Java. So a method that takes an object of type A and, internally, store it inside an Option, might well need to store a null inside that option.

    For example, let's say you have a method that takes the head of a list, checks if that head correspond to a key in a store, and then return true if it is. One might implement it like this:

    def isFirstAcceptable(list: List[String], keys: Set[String]): Boolean =
        list.headOption map keys getOrElse false
    

    So, here's the thing... if the that inside list and keys come from some Java API, they both may well contain null! If Some(null) wasn't possible, then isFirstAcceptable(List[String](null), Set[String](null)) would return false instead of true.

    0 讨论(0)
  • 2020-12-15 03:17

    I think the others in the thread do a good job explaining why Some(null) "should" exist, but if you happen to be getting Some(null) somewhere and want a quick way to turn it into None, I've done this before:

    scala> val x: Option[String] = Some(null)
    x: Option[String] = Some(null)
    
    scala> x.flatMap(Option(_))
    res8: Option[String] = None
    

    And when the starting Option is a legit non-null value things work as you probably want:

    scala> val y: Option[String] = Some("asdf")
    y: Option[String] = Some(asdf)
    
    scala> y.flatMap(Option(_))
    res9: Option[String] = Some(asdf)
    
    0 讨论(0)
  • 2020-12-15 03:18

    As a simple thought experiment, consider two lists of Strings, one of length 5 and one of length 20.

    Because we're running on the JVM, it's possible to insert null as a valid element into one of these lists - so put that in the long list as element #10

    What, then, should the difference be in the values returned from the two following expressions?

    EDIT: Exchanged get for lift, I was thinking of maps...

    shortList.lift(10) //this element doesn't exist
    longList.lift(10)  //this element exists, and contains null
    
    0 讨论(0)
  • 2020-12-15 03:19

    Much of Scala's WTFs can be attributed to its need for compatibility with Java. null is often used in Java as a value, indicating, perhaps the absence of a value. For example hashMap.get(key) will return null if the key is not matched.

    With this in mind, consider the following possible values from wrapping a null returning method in an Option:

    if (b) Some(hashMap.get(key)) else None
    // becomes -->
    None // the method was not invoked;
    Some(value) // the method was invoked and a value returned; or
    Some(null) // the method was invoked and null was returned.
    

    Some(null) seems sufficiently distinct from None in this case to warrant allowing it in the language.

    Of course if this is not desirable in your case then simply use:

    if (b) Option(hashMap.get(key)) else None
    // becomes -->
    None // the method was not invoked or the mapped value was null; or
    Some(value) // the method was invoked and a value returned
    
    0 讨论(0)
  • 2020-12-15 03:37

    Because Option is considered to be a Functor and being a Functor means:

    1. Has unit function (apply or just Option("blah") in Scala)
    2. Has map function which transforms value from T=>B but not a context
    3. Obeys 2 Functor laws - identity law and associative law

    In this topic the main part is #2 - Option(1).map(t=>null) can not transform context. Some should remain. Otherwise it brakes associative law!

    Just consider the following laws example:

    def identity[T](v: T) = v
    def f1(v: String) = v.toUpperCase
    def f2(v: String) = v + v
    def fNull(v: String): String = null
    
    val opt = Option("hello")
    
    //identity law
    opt.map(identity) == opt //Some(hello) == Some(hello)
    
    //associative law
    opt.map(f1 _ andThen f2) == opt.map(f1).map(f2) //Some(HELLOHELLO) == Some(HELLOHELLO)
    opt.map(fNull _ andThen f2) == opt.map(fNull).map(f2) //Some(nullnull) == Some(nullnull)
    

    But what if Option("hello").map(t=>null) produced None? Associative law would be broken:

    opt.map(fNull _ andThen f2) == opt.map(fNull).map(f2) //Some(nullnull) != None
    

    That is my thought, might be wrong

    0 讨论(0)
提交回复
热议问题