Skip to content

Forward referencing implicit object via import creates inconsistent behaviour #3466

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

Open
scabug opened this issue May 21, 2010 · 9 comments
Open
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) typer
Milestone

Comments

@scabug
Copy link

scabug commented May 21, 2010

The following code behaves inconsistently when executed as it creates a forward reference to Wanted.Default:

object Wants {

  implicit val nope = new AnyRef with Wanted

  def main(args: Array[String]): Unit = {
    import Wanted._
    println(nope eq implicitly[Wanted])
    println(Wanted.Default eq implicitly[Wanted])
    println(nope eq implicitly[Wanted])
  }
}

trait Wanted

object Wanted {
  implicit object Default extends Wanted
}

It produces the following output:

true
true
false

When moving object Wants to the bottom of the file the expected output is produced.

@scabug
Copy link
Author

scabug commented May 21, 2010

Imported From: https://issues.scala-lang.org/browse/SI-3466?orig=1
Reporter: Moritz Uhlig (muhlig)
See #5197

@scabug
Copy link
Author

scabug commented May 21, 2010

@paulp said:
Also interesting is this alteration:

  implicit lazy val Default = new AnyRef with Wanted
  // implicit object Default extends Wanted

which fails to compile:

a.scala:8: error: ambiguous implicit values:
 both lazy value Default in object Wanted of type => java.lang.Object with Wanted
 and value nope in object Wants of type => java.lang.Object with Wanted
 match expected type Wanted
    println(Wanted.Default eq implicitly[Wanted])
                                        ^
a.scala:9: error: ambiguous implicit values:
 both lazy value Default in object Wanted of type => java.lang.Object with Wanted
 and value nope in object Wants of type => java.lang.Object with Wanted
 match expected type Wanted
    println(nope eq implicitly[Wanted])
                              ^
two errors found

I'd formed this idea that the existence of both lazy vals and object members is something of an accident of history and that they may be unified down the road. If true we will need to ferret out these inconsistencies; if false it'd be nice if we could document them.

@scabug
Copy link
Author

scabug commented May 21, 2010

Moritz Uhlig (muhlig) said:
Actually this is the way it is described in the SLS �7.2 as far as I understand it. Wanted.Default is an implicit value of the type Wanted.Default.type that extends Wanted (i.e. not only of type Wanted). Following the rules defined in that section it gets selected because it is the most specific argument provided. That would explain why you get the same output if you change it e.g. to

implicit lazy val Default = new Something with Wanted

So even if you would unify them - in this case the problem would remain unless you change the rules for providing implicit arguments.

Even more confusing is this one:

case class X(y: Int)

implicit def int2xM(i: Int) = X(i)

implicit val int2xF: Int => X = X(_)

implicit object int2xO { def apply(i: Int) = X(i) }

def action[A <% X](a: A): X = a

Compiles fine - but without carefully reading the SLS you have no idea what is happening here (it's object before val before def in this case).

@scabug
Copy link
Author

scabug commented Oct 2, 2013

@OlegYch said:

import scalaz._, Scalaz._
 
  class A {
    def F = new A === new A
  }
  object A {
    implicit object AEqual extends Equal[A] {
      def equal(a1: A, a2: A): Boolean = a1 == a2
    }
  }

this kind of code compiles for me with full recompilation with 2.10.2 and 2.10.3 and sbt 0.13, but stops compiling (implicit not found) with incremental compilation unless i move object A to the top of the file or replace object AEqual with val AEqual: Equal[A] = new Equal[A] (note the explicit type), i also spuriously get the message from #5197

@SethTisue
Copy link
Member

someone want to take a look and see whether this should remain open?

@OlegYch
Copy link

OlegYch commented Mar 19, 2020

@SethTisue it fails to compile on 2.13.1 because 'object lacks explicit result type'

@joroKr21
Copy link
Member

The issue persist in Scala 2.13.1 😱

@OlegYch
Copy link

OlegYch commented Mar 19, 2020

i was referring to my example though, the original bug still reproduces

@SethTisue SethTisue added this to the Backlog milestone Mar 19, 2020
@SethTisue SethTisue added typer fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) labels Mar 19, 2020
@SethTisue
Copy link
Member

Dotty requires a type annotation on nope, and if you supply it, prints false true false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) typer
Projects
None yet
Development

No branches or pull requests

5 participants