Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Scala convert Int to Double?

Tags:

scala

coercion

val d: Double = 42

When I try to find implicit conversion via intellij, nothing interesting comes up. Also, Int isn't a subtype of Double. So how does Scala do it?

like image 505
allidoiswin Avatar asked Mar 08 '18 00:03

allidoiswin


People also ask

How do you convert an int to a double?

We can convert int value to Double object by instantiating Double class or calling Double. valueOf() method.

Can a double turn into an int?

We can convert double to int in java using typecasting. To convert double data type into int, we need to perform typecasting. Typecasting in java is performed through typecast operator (datatype).

What is double in Scala?

In Scala, Double is a 64-bit floating point number, which is equivalent to Java's double primitive type. The -(x: Double) method is utilized to get the difference of given Double and Double value. Method Definition – def -(x: Char): Double. Returns – Returns the difference of this value and x.

What happens when double is converted to int?

round() method converts the double to an integer by rounding off the number to the nearest integer. For example – 10.6 will be converted to 11 using Math. round() method and 1ill be converted to 10 using typecasting or Double.


1 Answers

Long story short: it's not an ordinary implicit conversion on some companion object, the numerical types get a special treatment.


If we run scala -print on this script:

val d: Double = 42

we obtain:

package <empty> {
  object Main extends Object {
    def main(args: Array[String]): Unit = {
      new <$anon: Object>();
      ()
    };
    def <init>(): Main.type = {
      Main.super.<init>();
      ()
    }
  };
  final class anon$1 extends Object {
    private[this] val d: Double = _;
    <stable> <accessor> private def d(): Double = anon$1.this.d;
    def <init>(): <$anon: Object> = {
      anon$1.super.<init>();
      anon$1.this.d = 42.0;
      ()
    }
  }
}

In the desugared code, we see a double literal 42.0, but no invocations of any conversion functions (e.g. from Predef). Thus, the conversion from Int to Double must take place not at runtime, but at earlier stages of compilation.

The section 3.5.3 of the specification tells us that Int weakly conforms to Double because of the transitivity of the weak conformance relation <:w:

Int <:w Long <:w Float <:w Double

Furthermore, Section 6.26.1 (Value Conversions) tells us that rules for numeric widening are applicable if an expression e of type T appears in position where an expression of type pt is expected and T weakly conforms to pt. In this case, we can apply the rule with

  • expression e = 42
  • type of expression T = Int
  • expected type pt = Double

Thus, 42 is converted to 42.0 using toDouble. Since it's a constant that can be processed at compile time, we don't see the toDouble in the desugared code. However, if we desugar a similar program with a non-constant value

val d: Double = (new scala.util.Random).nextInt(42)

we obtain:

package <empty> {
  object Main extends Object {
    def main(args: Array[String]): Unit = {
      new <$anon: Object>();
      ()
    };
    def <init>(): Main.type = {
      Main.super.<init>();
      ()
    }
  };
  final class anon$1 extends Object {
    private[this] val d: Double = _;
    <stable> <accessor> private def d(): Double = anon$1.this.d;
    def <init>(): <$anon: Object> = {
      anon$1.super.<init>();
      anon$1.this.d = new scala.util.Random().nextInt(42).toDouble();
      ()
    }
  }
}

and the toDouble is there, as specified.

like image 193
Andrey Tyukin Avatar answered Oct 06 '22 18:10

Andrey Tyukin