Max Wong
Max Wong

Reputation: 750

How to suppress automatic conversion from Long to Double when creating an array containing type AnyVal

I was trying to create an array containing all Int, Long and Double types. However, I found that the Long and Int types are automatically converted to Double. Here's a minimal example,

object HelloWorld {
  def main(args: Array[String]): Unit = {  
    val types = Array[Byte]('i', 'l', 'd', 'd')
    val array = Array[String]("1", "2000000", "20.0", "2020.0")
    val values = array.zip(types) map { case (s, t) => 
      t match {
        case 'i' => s.toInt
        case 'l' => s.toLong
        case 'd' => s.toDouble
      }
    }
    values.foreach { println }
  }
}

The result is

1.0
2000000.0
20.0
2020.0

How can I avoid such conversion? Thanks.

Upvotes: 2

Views: 397

Answers (3)

Suma
Suma

Reputation: 34423

This is because the compiler tries to come with a least surprising type of the match expresion, which is a type all those types (Int, Long and Double) can be converted to:

t match {
    case 'i' => s.toInt
    case 'l' => s.toLong
    case 'd' => s.toDouble
  }

You can use a type ascription or an assignment to provide your own type instead, which may be Numeric or AnyVal.

case (s, t) => (t match {
    case 'i' => s.toInt
    case 'l' => s.toLong
    case 'd' => s.toDouble
  }):AnyVal

or

    val result: AnyVal = t match {
      case 'i' => s.toInt
      case 'l' => s.toLong
      case 'd' => s.toDouble
    }
    result

Another alternative is to use the :AnyVal type ascription on any of the case results, which will also make the compiler to give up trying coming up with a more sensible type:

    t match {
      case 'i' => s.toInt:AnyVal
      case 'l' => s.toLong
      case 'd' => s.toDouble
    }

Upvotes: 2

Mario Galic
Mario Galic

Reputation: 48430

The expression

t match {
  case 'i' => s.toInt
  case 'l' => s.toLong
  case 'd' => s.toDouble
}

infers to Double because Scala 2 calculates weak least upper bound. One option is to use type ascription to tell the compiler explicitly the regular least upper bound, for example,

(t match {
  case 'i' => s.toInt
  case 'l' => s.toLong
  case 'd' => s.toDouble
}): AnyVal

Scala 3 drops the notion of weak conformance

drops the general notion of weak conformance, and instead keeps one rule: Int literals are adapted to other numeric types if necessary.

so your example would work as intended.

Upvotes: 3

Alonso del Arte
Alonso del Arte

Reputation: 1025

This is not the cleverest way: make a list of lists, then flatten.

val types = List[Byte]('i', 'l', 'd', 'd')
val array = List[String]("1", "2000000", "20.0", "2020.0")
val values = array.zip(types) map { 
  case (s, t) => t match {
    case 'i' => List(s.toInt)
    case 'l' => List(s.toLong)
    case 'd' => List(s.toDouble)
  }
}
values.flatten

Here's the Scastie snippet: https://scastie.scala-lang.org/tpLbvlg1TrKmQsqeZRsDTg

P.S. Arrays are provided in Scala mostly for the sake of Java interoperability. Otherwise prefer lists.

Upvotes: 0

Related Questions