Scala explanation for understanding with option

I have the following definition:

def f: Option[String] = Some(null) 

The following evaluates the value of None:

 for {x:String <- f} yield { x } 

The following expression takes the value Some (null):

 for {x <- f} yield { x } 

The following expression takes the value Some (null):

 f.map((x:String) => x) 

I wonder why there are differences between them?

+5
source share
2 answers

Desaurization occurs in the parser, so -Xprint:parser shows the difference:

 $ scala -Xprint:parser Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111). Type in expressions for evaluation. Or try :help. scala> for (s: String <- (Some(null): Option[String])) yield s [[syntax trees at end of parser]] // <console> package $line3 { object $read extends scala.AnyRef { def <init>() = { super.<init>(); () }; object $iw extends scala.AnyRef { def <init>() = { super.<init>(); () }; object $iw extends scala.AnyRef { def <init>() = { super.<init>(); () }; val res0 = (Some(null): Option[String]).withFilter(((check$ifrefutable$1) => check$ifrefutable$1: @scala.unchecked match { case (s @ (_: String)) => true case _ => false })).map(((s: String) => s)) } } } } res0: Option[String] = None 

This surprises me because I thought that filtering in this way was a feature that people wanted, but not implemented.

A type template is just an instance of test, so null cannot run this test.

Without a filter:

 scala> for (s <- (Some(null): Option[String])) yield s [[syntax trees at end of parser]] // <console> package $line4 { object $read extends scala.AnyRef { def <init>() = { super.<init>(); () }; object $iw extends scala.AnyRef { def <init>() = { super.<init>(); () }; object $iw extends scala.AnyRef { def <init>() = { super.<init>(); () }; val res1 = (Some(null): Option[String]).map(((s) => s)) } } } } res1: Option[String] = Some(null) 

In 2.9:

 $ scala29 Welcome to Scala version 2.9.3 (OpenJDK 64-Bit Server VM, Java 1.6.0_38). Type in expressions to have them evaluated. Type :help for more information. scala> for (s: String <- (Some(null): Option[String])) yield s res0: Option[String] = Some(null) 

therefore the filtering function was added in 2.10.x.

Edit: so this is actually what you are not getting:

 scala> for (s: String <- (Some("x"): Option[Any])) yield s <console>:12: error: type mismatch; found : String => String required: Any => ? for (s: String <- (Some("x"): Option[Any])) yield s ^ 
+5
source

Well ... the first thing I will say is that "When in Scala -land, stay away from the null monster whenever possible." They are dangerous.

Now ... to understand this behavior, the first thing you need to try in Scala -shell is the following,

 scala> val n = null n: Null = null 

So ... Scala null has an instance of this null class.

Now ... let's see what happens when we mix this null with Option ,

 scala> val nullOpt1 = Option(null) nullOpt1: Option[Null] = None scala> val nullOpt2 = Some(null) nullOpt2: Some[Null] = Some(null) 

Notice the difference ... between the two ... So basically Scala people thought there might be people who want to wrap null in Option ... so they let them explicitly use Some.apply to wrap this null in Option Where, when the use of Option.apply behaves more "reasonably" and gives you None when trying to wrap null .

Now ... first, let's see how map implemented for Option ,

 final def map[B](f: A => B): Option[B] = if (isEmpty) None else Some(f(this.get)) 

And now ... it should be clear that "why Some(null).map((x: String) => x) gives you Some(null) ?".

As for understanding for ... cases, which will require little understanding of how for implemented for Option using Repr . And the behavior will become clear.

+1
source

Source: https://habr.com/ru/post/1262401/


All Articles