Skip to content

Empty package visibility underspecified or just confusing #7891

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

Closed
som-snytt opened this issue Jan 4, 2020 · 9 comments · Fixed by #13593
Closed

Empty package visibility underspecified or just confusing #7891

som-snytt opened this issue Jan 4, 2020 · 9 comments · Fixed by #13593
Assignees
Milestone

Comments

@som-snytt
Copy link
Contributor

minimized code

// ok in one compilation unit
def f = "hello, world"

package p {
  @main def m = println(f)
}
// fonly.scala
def f = "hello, world"

// ponly.scala
package p {
  @main def m = println(f)
}

Compiled together or separately:

➜  dotc ponly.scala fonly.scala
-- [E006] Unbound Identifier Error: ponly.scala:5:24 ---------------------------
5 |  @main def m = println(f)
  |                        ^
  |                        Not found: f

longer explanation available when compiling with `-explain`
1 error found

expectation

Binding of f shouldn't depend on compilation unit, but moreover, members of the empty package should be visible only to members of the empty package; or specify that they are visible in the current compilation unit.

Other restrictions may apply. Cf #7650

Related confusion in Scala 2: scala/bug#10927

@odersky
Copy link
Contributor

odersky commented Jan 4, 2020

I vote for:

or specify that they are visible in the current compilation unit.

@odersky odersky self-assigned this Jan 6, 2020
@dwijnand
Copy link
Member

I vote for:

or specify that they are visible in the current compilation unit.

Are there many things in the language where the current compilation unit matters (outside of the obvious sealed)?

We've had this discussion before (and I can't remember about what exactly) but, personally, while I can appreciate that it would be a bit of a stutter step if as soon as you introduced package p in the file f is strangely not visible, I still think that's better than having to bear in mind if things are within the same file or not.

That's why I ask: should I just come to terms with the fact that this detail matters?

@dwijnand
Copy link
Member

We've had this discussion before (and I can't remember about what exactly)

(Found it, it was to do with imports: scala/bug#11593)

@som-snytt
Copy link
Contributor Author

@dwijnand There's an old scala2 ticket where paulp was pulling his hair out about this stuff. (Number 9552.) Tooling can assist, but ultimately, the answer to "I can't reason about this" is "Don't write code that way." Prefer FP to OOP, composition to inheritance, etc.

The empty package and top-level defs is worth attention because, as a newbie, I'm likely to be trying out code that is the opposite of best practice.

Another recent idea, which I haven't promoted, is to enable denotating a directory of files as a single compilation unit, scalac mydir. They would be compiled as sibling contexts so that naming works right. My only idea for how to indicate that was to name the dir mydir.scala.

@dwijnand
Copy link
Member

I consider defining multiple packages within a file to be quite an advanced feature, don't you? As such, I don't think the newbie excuse holds.

@som-snytt
Copy link
Contributor Author

Here, it told me to add the braces, and then I added the f after new. It didn't tell me not to use new.

I could have switched the order of the main and package.

Obviously, this test throws.

@main def test() = println(new f.C().c)

package f {

class C {
  val s = "hello"
  def c: String = f"$s%-s"
}

}

@dwijnand
Copy link
Member

As a beginner why did you introduce a package block?

@som-snytt
Copy link
Contributor Author

As a non-beginner but as a Scala 2 refugee, I tried:

@main def test() = ???
package f
class C

whereas I might have done better with

@main def test() = println(f.C().c)

val s = "hi"

package f
  class C
    def c = f"$s"

I usually put experimental classes in packages so they wind up in subdirs of my snippets dir.

@som-snytt
Copy link
Contributor Author

I only just caught up with this change in behavior because https://github.com/lampepfl/dotty/blob/release-3.1.1/tests/untried/neg/warn-unused-imports.scala#L9 no longer compiles.

The implementation wound up reversing the previous vote from Jan 2020, that empty package definitions would be in scope in the same file.

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

Successfully merging a pull request may close this issue.

4 participants