Than21
Than21

Reputation: 321

Failed implicit conversion in scala ensuring block

I am using scalac 2.12.1 to compile the following program without any options:

import scala.language.implicitConversions

case class Int32(v : Int) {
}
case class Int64(v : BigInt) {
    def > (that : Int64) = this.v > that.v
    def <= (that : Int64) = this.v <= that.v
}
object implicits {
    implicit def int32Toint64(input : Int32) = Int64(BigInt(input.v))
}
import implicits._

class myTest {
    def max(x: Int64, y: Int32) : Int64 = {
        if (x > y)
            x
        else
            y  // If this is replaced with int32Toint64(y) it works !
    } ensuring(res => x <= res && y <= res) // <= error: missing parameter type for 'res'
}

The above program fails to compile with the error indicated in the comment. My expectation was that the implicit conversion int32Toint64 will automatically take effect. Note that if I do the conversion explicitly, i.e., if I replace y with int32Toint64(y), then the program compiles successfully. So I am puzzled. Why do I see this behavior ? Is there a way to prevent this error without the explicit conversion ?

Thanks !

Upvotes: 2

Views: 58

Answers (1)

Andrey Tyukin
Andrey Tyukin

Reputation: 44957

This works:

class myTest {
    def max(x: Int64, y: Int32) : Int64 = {
        if (x > y)
            x
        else
            (y : Int64)
    } ensuring(res => x <= res && y <= res)
}

This also works:

class myTest {
    def max(x: Int64, y: Int32) : Int64 = ({
        if (x > y)
            x
        else
            y
    }: Int64) ensuring(res => x <= res && y <= res)
}

This obviously doesn't work:

class myTest {
    def max(x: Int64, y: Int32) : Int64 = {
        if (x > y)
            x
        else
            y
    } ensuring((res: Int64) => x <= res && y <= res)
}

Why? Look at this expression in isolation:

    {
        if (x > y)
            x
        else
            y
    }

What can a compiler possibly derive about it, if the type is not ascribed explicitly? It will derive something like Serializable, or even AnyRef. What else could it do? The typechecker works in a very straight forward fashion. It just looks at an expression, tries to derive the most precise type of it, and if no type is prescribed from the outside, it doesn't try to cast anything implicitly. And it does not start searching in remote corners of your code for additional type hints. In this case, ensuring ( ... ) is neither part of this expression, nor does it allow the explicit return type ascription : Int64 = to trickle down.

I guess the best way to understand why this is obvious is to write a little typechecker for the simply typed lambda calculus: it is very simple, but it already exhibits exactly the same behavior in similar situations.

Upvotes: 2

Related Questions