Shadowing rules: theory vs practice — a SLS/scalac bug?

86 views
Skip to first unread message

Paolo Giarrusso

unread,
Dec 16, 2012, 4:08:07 PM12/16/12
to scala-i...@googlegroups.com
Our friend the SLS tells us that "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." (Ch. 2). Testing scalac behavior suggests that explicit imports have lower precedence than definitions in the same package but in other compilation units; if that were the case imports couldn't shadow definitions. That doesn't sound right, does it? A simple example will show that the spec and scalac don't agree here. (Or, possibly, the language of the spec is just confusing, but that should still be fixed).
Should this seems theoretical, this issue came up while fixing a compilation error in SBT, which only appears within Eclipse (and not when compiling with SBT) - the reason for the inconsistency seems yet different.

Here's the example:

File1.scala:

package P {
  object X { val x = 1; val y = 2 }
}
File2.scala:

package Q {
  object X { val x = true; val y = "" }
}
Test.scala:

package P { // ‘X’ bound by package clause
  import Q.X //<<<
  object A {
    println("L4: "+X) // ‘X’ refers to ‘P.X’ here
  }
}
Result:

[warn] /Users/pgiarrusso/Documents/Research/Sorgenti-Sync/Scala/importSpecificity/src/main/scala/Test.scala:2: imported `X' is permanently hidden by definition of object X in package P
[warn]   import Q.X
[warn]          ^
[warn] one warning found

So, it seems that P.X, even though declared elsewhere, has higher priority. Now let's try to import Q.X in an inner scope. Since an explicit import has lower priority, according to the spec this should cause an ambiguity error, and make it impossible to import any X within package P. Pretty bad, uh? Luckily, not the case.

package P { // ‘X’ bound by package clause
  object A {
    import Q.X //import Q._ also works.
    println("L4: "+X) // ‘X’ refers to ‘Q.X’ here
  }
}
scala> P.A
L4: Q.X$@4f388e
res0: P.A.type = P.A$@5109f2ca

As you see, the code compiles, and P.A is a Q.X. Following the spec, we can only conclude that P imports X with priority lower than wildcard imports, contradicting our earlier contradiction. How's that possible? And especially, why don't I just look up the priority of the bindings to package members?

  1. Definitions and declarations that are [...] or made available by a package clause in the same compilation unit where the definition occurs have highest precedence.
  2. Explicit imports have next highest precedence. 
  3. Wildcard imports have next highest precedence.
  4. Definitions made available by a package clause not in the compilation unit where the definition occurs have lowest precedence.
I'm a bit confused about the difference between 1 and 4, and that's why I tried to find out practically what happens. My interpretation is as follows.
When we compile Test.scala and we process the "package P" declaration, P.X should enter in scope. Since X is defined in another compilation unit (File1.scala), rule 4 should always apply, and P.X should have lowest priority. In the second case, this matches practice, and this is good. However, in the first case, P.X behaves as if it had highest priority - which seems clearly inconsistent. This also seems undesirable to me - why should an explicit import be ignored?

Overall, what do you think? Should I file a ticket?
Cheers,
--
Paolo G. Giarrusso - Ph.D. Student, Philipps-University Marburg
http://www.informatik.uni-marburg.de/~pgiarrusso/

Paul Phillips

unread,
Dec 16, 2012, 4:42:27 PM12/16/12
to scala-i...@googlegroups.com

On Sun, Dec 16, 2012 at 1:08 PM, Paolo Giarrusso <p.gia...@gmail.com> wrote:
Our friend the SLS tells us that "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." (Ch. 2).

It was changed three years ago, but apparently only in the version in "the vault".


Martin Odersky added a comment - 27/Oct/09 1:08 PM

I tried to change the behavior to match the spec, but lots of code
broke, so I backed out and made the spec conform to current behavior. It
now reads:

Bindings of different kinds have a precedence defined on them:
Definitions and declatarations have the highest precedence, no matter
whether they are local, or inherited, or made available by a package
clause. Explicit imports have the next highest precedence and wildcard
imports have the lowest precedence.

That I spend so much time on specifiction issues is how I knew to sift through closed tickets for forensic evidence; this had to have come up before.

Paolo G. Giarrusso

unread,
Dec 17, 2012, 9:10:24 AM12/17/12
to scala-i...@googlegroups.com
I added a link to this discussion (with a short summary), reopened the bug and reassigned it to Scala Reviewer anew, so that it will be reassigned depending on current schedules - I hope that's the best course of action.

Best,
Paolo
Reply all
Reply to author
Forward
0 new messages