New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contravariance mucks with implicit resolution #2509

Closed
scabug opened this Issue Oct 22, 2009 · 11 comments

Comments

Projects
None yet
5 participants
@scabug

scabug commented Oct 22, 2009

A condition under which the most-specific implicit is not being selected:

// Test.scala
class A
class B extends A

trait Y {
  def value: String
} 

trait X[-T] { // if I make X invariant, this works
  def y(t: T): Y
}

object XA extends X[A] {
  def y(a: A) = new Y { def value = a.getClass + ": AValue" }
}

object XB extends X[B] {
  def y(b: B) = new Y { def value = b.getClass + ": BValue" }
}

object Test {
  implicit def f[T](t: T)(implicit x: X[T]): Y = x.y(t)
  implicit val xa: X[A] = XA
  implicit val xb: X[B] = XB

  def main(argv: Array[String]) {
    val a = new A
    val b = new B
    println("A: " + a.value)
    println("B: " + b.value)
  }
}

gives:

$$ scala Test
A: class A: AValue
B: class B: AValue

Making X invariant in T gives a correct result, but of course is much less flexible.

@scabug

This comment has been minimized.

scabug commented Oct 22, 2009

Imported From: https://issues.scala-lang.org/browse/SI-2509?orig=1
Reporter: Kris Nuttycombe (nuttycom)

@scabug

This comment has been minimized.

scabug commented Oct 27, 2009

@adriaanm said:
this is due to a known limitation of our type inference algorithm (contravariant type params are problematic wrt inference)

@scabug

This comment has been minimized.

scabug commented Nov 18, 2009

@adriaanm said:
Actually, what I said is a little imprecise:

type inference&implicit search yields:

    println("A: " + f[A](a)(xa).value)
    println("B: " + f[B](b)(xa).value)

but that's what's expected because xa is the value with the most specific type: X[A], as X[A] <: X[B] (since B <: A and X is contravariant in its first type argument)

@scabug

This comment has been minimized.

scabug commented Nov 18, 2009

Kris Nuttycombe (nuttycom) said:
What I find surprising about this is that specificity is conflated with the direction of the variance. At least to my mind, variance is associated with substitutability, whereas specificity is a unidirectional relation in the direction of covariance.

The concepts aren't totally orthogonal; it's more like there should be a distinction between subclassing (where subclasses are always more specific) and subtyping, where an instance of a subtype is always substitutable for an instance of the supertype.

@scabug

This comment has been minimized.

scabug commented Sep 4, 2012

@paulp said:
Noting for any future database searchers that as far as I'm concerned I fixed this.

Discussion: https://groups.google.com/forum/#!topic/scala-language/ZE83TvSWpT4

Implementation: https://github.com/paulp/scala/tree/topic/contrarivariance

@scabug

This comment has been minimized.

scabug commented May 29, 2016

@milessabin said (edited on May 29, 2016 7:56:40 AM UTC):
In the light of this Dotty commit I think we should un-Won't Fix this ticket and deal with it here too.

@scabug

This comment has been minimized.

scabug commented May 29, 2016

@dwijnand said:
(here's the commit SHA that eventually made it into lampepfl/dotty: lampepfl/dotty@8954026)

@scabug

This comment has been minimized.

scabug commented May 29, 2016

@soc said:
Agree. Would be nice to get this into 2.12 as a flag to allow all the "base" libraries to play with it. Without it this would delay even thinking about integrating some fundamental typeclasses into the std lib for years.

@scabug

This comment has been minimized.

scabug commented May 30, 2016

Tongfei Chen (ctongfei) said:
I'd very much like to see this fixed in 2.12. Spire/Cats/Scalaz/... are in desperate need of this :-)

@scabug

This comment has been minimized.

scabug commented May 30, 2016

Guillaume Martres (Smarter) said (edited on May 30, 2016 4:03:19 PM UTC):
For reference, lampepfl/dotty#1246 (comment) documents the sort of issues with existing implicits that might pop up if you change that rule, and how to fix them.

@scabug scabug added the implicits label Apr 7, 2017

@scabug scabug added this to the Backlog milestone Apr 7, 2017

@milessabin milessabin modified the milestones: Backlog, 2.13.0-M4 Mar 2, 2018

milessabin added a commit to milessabin/scala that referenced this issue Mar 6, 2018

Downwards comparisons for implicit search and overloading resolution
This is a backport of the following Dotty change to scalac,

lampepfl/dotty@8954026

As in the Dotty implementation the specificity comparison which is used
for overload resolution and implicit selection is now performed as-if
all contravariant positions in top level type constructors were
covariant.

Currently this breaks test/files/run/t2030.scala in exactly the same way
as in Dotty as reported here,

lampepfl/dotty#1246 (comment)

and in this PR it has been changed to a neg test. However,
test/files/run/t2030.scala passes when this PR is combined with,

scala#6139

so if/when that is merged it can be switched back to a pos test.

Fixes scala/bug#2509. Fixes scala/bug#7768.

milessabin added a commit to milessabin/scala that referenced this issue Mar 22, 2018

Downwards comparisons for implicit search and overloading resolution
This is a backport of the following Dotty change to scalac,

lampepfl/dotty@8954026

As in the Dotty implementation the specificity comparison which is used
for overload resolution and implicit selection is now performed as-if
all contravariant positions in top level type constructors were
covariant.

Currently this breaks test/files/run/t2030.scala in exactly the same way
as in Dotty as reported here,

lampepfl/dotty#1246 (comment)

and in this PR it has been changed to a neg test. However,
test/files/run/t2030.scala passes when this PR is combined with,

scala#6139

so if/when that is merged it can be switched back to a pos test.

Fixes scala/bug#2509. Fixes scala/bug#7768.

milessabin added a commit to milessabin/scala that referenced this issue Mar 29, 2018

Downwards comparisons for implicit search and overloading resolution
This is a backport of the following Dotty change to scalac,

lampepfl/dotty@8954026

As in the Dotty implementation the specificity comparison which is used
for overload resolution and implicit selection is now performed as-if
all contravariant positions in top level type constructors were
covariant.

Currently this breaks test/files/run/t2030.scala in exactly the same way
as in Dotty as reported here,

lampepfl/dotty#1246 (comment)

and in this PR it has been changed to a neg test. However,
test/files/run/t2030.scala passes when this PR is combined with,

scala#6139

so if/when that is merged it can be switched back to a pos test.

Fixes scala/bug#2509. Fixes scala/bug#7768.
@lrytz

This comment has been minimized.

Member

lrytz commented Apr 19, 2018

@SethTisue SethTisue modified the milestones: 2.13.0-M4, 2.13.0-M5 May 14, 2018

milessabin added a commit to milessabin/scala that referenced this issue Jul 26, 2018

Downwards comparisons for implicit search and overloading resolution
This is a backport of the following Dotty change to scalac,

lampepfl/dotty@8954026

As in the Dotty implementation the specificity comparison which is used
for overload resolution and implicit selection is now performed as-if
all contravariant positions in top level type constructors were
covariant.

Currently this breaks test/files/run/t2030.scala in exactly the same way
as in Dotty as reported here,

lampepfl/dotty#1246 (comment)

and in this PR it has been changed to a neg test. However,
test/files/run/t2030.scala passes when this PR is combined with,

scala#6139

so if/when that is merged it can be switched back to a pos test.

Fixes scala/bug#2509. Fixes scala/bug#7768.

milessabin added a commit to milessabin/scala that referenced this issue Jul 26, 2018

Downwards comparisons for implicit search and overloading resolution
This is a backport of the following Dotty change to scalac,

lampepfl/dotty@8954026

As in the Dotty implementation the specificity comparison which is used
for overload resolution and implicit selection is now performed as-if
all contravariant positions in type constructors were covariant.

Currently this breaks test/files/run/t2030.scala in exactly the same way
as in Dotty as reported here,

lampepfl/dotty#1246 (comment)

and in this PR it has been changed to a neg test. However,
test/files/run/t2030.scala passes when this PR is combined with,

scala#6139

so if/when that is merged it can be switched back to a pos test.

Fixes scala/bug#2509. Fixes scala/bug#7768.

milessabin added a commit to milessabin/scala that referenced this issue Aug 6, 2018

Downwards comparisons for implicit search and overloading resolution
This is a backport of the following Dotty change to scalac,

lampepfl/dotty@8954026

As in the Dotty implementation the specificity comparison which is used
for overload resolution and implicit selection is now performed as-if
all contravariant positions in type constructors were covariant.

Fixes scala/bug#2509. Fixes scala/bug#7768.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment