Why does type inference only select a specific type of target link when considering implicit conversions?

Consider the following simple code for creating type types. In this first section, I can create an Identity class for any type.

 scala> trait Equals[A] { def equal(a1 : A, a2 : A) : Boolean } defined trait Equals scala> sealed trait Identity[A] { | def value : A | def ===(b : A)(implicit e : Equals[A]) = e.equal(value, b) | } defined trait Identity scala> implicit def ToIdentity[A](a : A) = new Identity[A] { val value = a } ToIdentity: [A](a: A)java.lang.Object with Identity[A] 

So, if I create a class of type Equals[Int] , now I have to use my types equal to:

 scala> implicit val EqualsInt = new Equals[Int] { def equal(i1 : Int, i2 : Int) = i1 == i2 } EqualsInt: java.lang.Object with Equals[Int] = $anon$1@7e199049 scala> 1 === 2 res1: Boolean = false scala> 1 === 1 res2: Boolean = true scala> 1 === 1D <console>:10: error: type mismatch; found : Double(1.0) required: Int 1 === 1D ^ 

Ok, so far so good. What happens if I create Equals[Any] ?

 scala> implicit val EqualsAny = new Equals[Any] { def equal(a1 : Any, a2 : Any) = a1 == a2 } EqualsAny: java.lang.Object with Equals[Any] = $anon$1@141d19 scala> 1 === 1D <console>:11: error: type mismatch; found : Double(1.0) required: Int 1 === 1D ^ 

But if I tell the compiler that my type is Any , not Int ...

 scala> (1 : Any) === 1D res6: Boolean = true 

So my question is: β€œWhy doesn't the compiler consider all types that 1 logically has?”

That is, I realized that a link of type Int logically has types Int , AnyVal and Any . Anyway, I researched a bit more, suggesting that the problem is related to covariance. I changed my Identity definition:

 scala> sealed trait Identity[+A] { | def value : A | def ===[B >: A : Equals](b : B) = implicitly[Equals[B]].equal(value, b) | } defined trait Identity 

This time I got an error:

 scala> 1 === 1D <console>:10: error: could not find implicit value for evidence parameter of type Equals[AnyVal] 1 === 1D ^ 

So, if I create Equals[AnyVal] , then this also works:

 scala> implicit val EqualsAnyVal = new Equals[AnyVal] { def equal(a1 : AnyVal, a2 : AnyVal) = a1 == a2 } EqualsAnyVal: java.lang.Object with Equals[AnyVal] = $anon$1@67ce08c7 scala> 1 === 1D res4: Boolean = true 

So, here I am assuming that the problem is related to Equals non- Equals . So I try again (but not creating Equals[AnyVal] ):

 scala> trait Equals[-A] { def equal(a1 : A, a2 : A) : Boolean } defined trait Equals scala> 1 === 1D res3: Boolean = true 

So, I can see what typer does here. But my question looks like this:: why doesn’t the tester ask the question (for my first example):

  • 1 is Int ; with implicits in scope, I can create an Identity[Int] and then use the === method. But this does not work, because the argument is not Int . Try to use alternative types for 1.
  • 1 is AnyVal ; With implicits in scope, I can create Identity[AnyVal] and then use === . But this does not work, because although the argument is AnyVal , there is no implicit Equals[AnyVal] . Try to use alternative types for 1.
  • 1 is Any ; With implicits in scope, I can create Identity[Any] and then use === . This works because both arguments are Any , and there are Equals[Any] in the scope.

Why does output type only consider the strictest type 1 (i.e. int)?

+4
source share
1 answer

What you see here is the priority implicit conversion added in Scala 2.8.

According to the Language Specification (pdf), section 7.2 :

If there are several suitable arguments that correspond to an implicit parameter type, the most specific one will be selected using the rules for resolving static overloads (Β§6.26.3).

It is also a mechanism that supports CanBuildFrom behavior in 2.8 collections .

+6
source

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


All Articles