Behavior of Scala for/comprehension implicit trans

2019-09-20 07:27发布

问题:

I'm trying to understand the behavior of Scala for-loop implicit box/unboxing of "numerical" types. Why does the two first fail but not the rest?

1) Fails:

scala> for (i:Long <- 0 to 10000000L) {}

      <console>:19: error: type mismatch;<br>
      found   : Long(10000000L)
      required: Int
              for (i:Long <- 0 to 10000000L) {}
                                  ^

2> Fails:

scala> for (i <- 0 to 10000000L) {}

      <console>:19: error: type mismatch;
      found   : Long(10000000L)
      required: Int
          for (i <- 0 to 10000000L) {}
                         ^

3) Works:

scala> for (i:Long <- 0L to 10000000L) {}

4) Works:

scala> for (i <- 0L to 10000000L) {}

回答1:

It has nothing to do with the for-loop:

0 to 1L   //error
0 to 1    //fine
0L to 1L  //fine
0L to 1   //fine

It's just because the to method available to Int expects an Int as its argument. So when you give it a Long it doesn't like it, and you get an error.

Here's the definition of the to method, found on RichInt:

def to(end: Int): Range.Inclusive = Range.inclusive(self, end)


回答2:

The desugaring and implicit transformation of numerical types is inconsistent i.e differ between the "for/comprehension" expressions compared to assignment operations. Please feel free to prove otherwise or at least point where the argument below is flawed:

In fact, during numeric assignment the Destination type is dominant.

var l:Long = 0 becomes:
val l: Long = 0L

var l:Long = 0.toInt becomes:
var l: Long = 0.toInt.toLong

During "for/comprehension" expressions the Source type is dominant:

for (i:Long <- 0 to 1000000000L) { } becomes:
0.to(1000000000L).foreach(((i: Long) => ()))

for (i <- 0L to 1000000000L) { } becomes: scala.this.Predef.longWrapper(0L).to(1000000000L).foreach[Unit](((i: Long) => ()))

(ps: output generated with the "-Xprint:typer -e" compiler flag. ds)