-
Notifications
You must be signed in to change notification settings - Fork 21
Clarify spec on precedence of definitions in the same package and imports supplied by the compiler #12513
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
Comments
I'm not sure what the picture is saying, but the spec goes on to say: A binding in some inner scope shadows bindings of lower precedence in the same scope as well as bindings of the same or lower precedence in outer scopes. The so-called "root imports" or "root contexts" are the outermost scopes, so they are shadowed by anything in source code. They work like an enclosing package in which your code is nested, as though you had written
so that anything in the root package is visible in mystuff (but may be shadowed by definitions in mystuff). I think the spec already says this, but of course clarifications are welcome. The text and its implementation have seen several iterations. The root contexts are also nested, so the order of |
Maybe I misunderstood something, but: Here its said that:
I assume that "imports which are supplied by the compiler" == "implicit imports" package myStuff
import java.lang._
import scala._
import scala.Predef._
//explicit imports go here... I can guess that combining this information
and
The resulting code is something like: package _root_
import java.lang._
import scala._
import scala.Predef._
package myStuff
//explicit imports go here... If so, then I can't see how it can be inferred from the current spec. |
No, they are not like imports, which is why "root imports" is a misnomer. It is as I described, which is more precise than the spec has it in the section about the "preamble". "These imports are taken as lowest precedence, so that they are always shadowed by user code, which may contain competing imports and definitions. They also increase the nesting depth as shown, so that later imports shadow earlier ones." Those words attempt to describe the behavior, but it's wrong. It's really just as though each root context were an enclosing package. Maybe that is the section that needs clarification. |
This also doesn't look like the best description. It's something in between...
|
It's compiler magic, but the mechanism is just an enclosing context. You could think of it like the "empty package", a package with no package prefix. I would argue that the empty package is equally strange. |
On the whole, I don't think that it will hurt splitting this:
into two items, in order it's consistent with what's written latter:
WDYT? |
I see what you mean, that it is explanatory, but it's also true that the spec covers the behavior. That is, root context is not lower precedence, it's an outer scope. Normal shadowing is at work. However, it really is compiler magic, so maybe what matters is whatever metaphor makes it palatable. It's also nice to minimize the number of rules. The other question is maybe the spec is ok, but there is a FAQ or overview doc that could clarify how it works. I should add that I considered what you suggest, which is plausible, but I realized it's not necessary. That was when I contributed a fix in this area. I'd suggest that if you make a 5th precedence level for it, also edit the "import" analogy. Just call it a magical introduction of symbols. You can't write it in code, so don't try to explain it in ordinary terms of the language. I think Lukas made a similar point back then. I think |
I can answer that Odersky is confident in how it works (and it works the same in Scala 3), with the reasoning: it should prefer what I wrote in my source file, not what someone else wrote somewhere else. In your example, the unwanted name binding in the wildcard import should have been excluded.
Some people are averse to wildcard imports, and certainly implicit resolution in Scala 3 is designed to reduce problems due to name collisions. |
Related bug #12566 where Seth asks how is binding of root package names defined? That related bug concerns the precedence of (Worth adding that there is no mention of "class path", which matters for classes in the empty package; packages are open, though won't that change in the modular era? That is an implementation detail about class paths.) A further observation on the last example about the difference between Java and Scala: Java has flat packages, so import really means import from other packages. (Or statically.) Scala's nested packages means lexical scoping of imports is meaningful. To say, "If I refactor imports, then I'll have to look at all the imports," is like saying, "If I refactor a variable name, I have to look at all the names [that might conflict]." |
The "enclosing package" analogy for "root contexts" breaks down because package-private members of a predef object are selectively available to user code depending on usual access rules. (Which makes them more like an import, or "in-between", as noted earlier.) |
https://scala-lang.org/files/archive/spec/2.13/02-identifiers-names-and-scopes.html
Currently, spec says:
It sounds like definitions in the same package and imports supplied by the compiler have the same precedence.
But looks like definitions in the same package have a higher precedence.
Otherwise, I would expect this code to produce some ambiguity error.
But it compiles and shows that definition in the same package is preferred
I think we could split spec item 4. into two items 4. and 5.
If you agree I could make a PR
The text was updated successfully, but these errors were encountered: