Skip to content
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

Should top level definitions access their wrapper objects and members of Any from Predef? #7713

Open
som-snytt opened this issue Dec 11, 2019 · 5 comments

Comments

@som-snytt
Copy link
Contributor

minimized code

$ cat anything.scala

def f = toString

def g = this.toString

class C(val name: String) {
  def this() = this(getClass.getName)
}

object Test {
  def main(args: Array[String]): Unit = {
    println(f)
    println(g)
    println(C().name)
  }
}
$ dotr Test
dotty.DottyPredef$@76707e36
anything$package$@184f6be2
dotty.DottyPredef$

expectation

Scala 2 recently stopped including members of Any in root imports from Predef.

That was previously visible in import ne.scala.

Using getClass in a constructor context was noticed in Akka test code.

Crafting a package from the compilation unit looks intentional here, so perhaps this is as well. And maybe there is nothing which says toString must mean this.toString in any context.

@som-snytt
Copy link
Contributor Author

Indeed the enclosing package is as documented: "The compiler generates synthetic objects that wrap toplevel definitions."

This this message might need a tweak. (Someone, not me, cracked a joke, so I had to try this out.)

$ cat thisly.scala

class C(c: C) {
  def this() = this(this)
}
$ dotc thisly.scala
-- Error: thisly.scala:3:20 ----------------------------------------------------
3 |  def this() = this(this)
  |                    ^^^^
  |                    this can be used only in a class, object, or template
one error found

@bishabosha bishabosha changed the title Unexpected top-level members of this and Any Should top level definitions access their wrapper objects? Dec 11, 2019
@bishabosha bishabosha changed the title Should top level definitions access their wrapper objects? Should top level definitions access their wrapper objects and members of Any from Predef? Dec 11, 2019
@som-snytt
Copy link
Contributor Author

The OP didn't include the Scala 2 ticket scala/bug#5389

@megri
Copy link
Contributor

megri commented Oct 3, 2021

I bumped into this today. It's easy enough to avoid by adding the this qualifier to top level definitions, but it's quite confusing.

@mbovel
Copy link
Member

mbovel commented Apr 14, 2023

We discussed the semantic of accessing this from top-level definitions recently with @Maeeen, @sjrd, @dwijnand and @abgruszecki because we notice that unqualified synchronized where desugared to Predef.synchronized, which sounds confusing.

There are three main questions:

  1. Should we allow direct references to this from top-level functions altogether?
  2. Should applications of Any/AnyRef-declared methods (like toString or synchronized) be desugared to this.meth
    or to Predef.meth. Currently the later is true. It seems to me that the former would make more sense, i.e. that this methods should have precedence over Prefef methods.
  3. Should we allow calling Any/AnyRef-declared methods on Predef and on generated synthetic objects for files?

Before reading this issue and https://docs.scala-lang.org/scala3/reference/dropped-features/package-objects.html, I was thinking that generated synthetic objects for files should not be part of the mental model of developers and that we should answer "no" to 1. and 3. (disallow references to this from top-level functions and calling Any/AnyRef-declared methods on Predef and on generated synthetic objects for files).

After reading them, the correct answer sounds less obvious to me. The documentation clearly states that generated synthetic objects for files are part of binary compatibility, and that you can runMain myFile$package to run the main function inside myFile.scala for example. So maybe these generated objects should be a thing after all?

As a first uncontroversial step, I would suggest to issue warnings for calls to both Predef.synchronized and <generated synthetic objects for files>.synchronized.

@som-snytt
Copy link
Contributor Author

@mbovel item 2 is intriguing also because scala/scala#10220 (comment)

This usage is ambiguous -- perhaps rightly so, because of the juxtaposition of the definition and usage.

It would not be ambiguous if toString were to become this.toString.

class C {
  override def toString = "CCC"

  class D {
    def s = toString  // ambiguous
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants