Scala Programming Language
  1. Scala Programming Language
  2. SI-3946

scalac allows overriding protected member with weaker privileges

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: Misc Compiler
    • Labels:
      None

      Description

      Given the the following files:

      `p/J.java`

      package p;
      public class J {
          protected void m() { return; }
      }
      

      `p/S.scala`

      package p
      class S extends J {
        override protected def m { }
      }
      

      Compiling them together with `scalac` gives the correct error message:

      lamppc11:bug1 luc$$ ../../target/pack/bin/scalac p/J.java p/S.scala
      p/S.scala:3: error: overriding method m in class J of type ()Unit;
       method m has weaker access privileges; it should be at least protected[p]
        override protected def m { }
                               ^
      one error found
      

      However, when compiling first the Java file, then the Scala file there's no error message:

      lamppc11:bug1 luc$$ javac p/J.java 
      lamppc11:bug1 luc$$ ../../target/pack/bin/scalac p/S.scala 
      lamppc11:bug1 luc$$
      

        Issue Links

          Activity

          Hide
          Lukas Rytz added a comment -

          fixed in r23627

          Show
          Lukas Rytz added a comment - fixed in r23627
          Hide
          Lukas Rytz added a comment -

          that was the wrong one...

          Show
          Lukas Rytz added a comment - that was the wrong one...
          Hide
          Lukas Rytz added a comment -

          (In r23673) close SI-3946. protected in java means access boundary is the package. review by dragos.

          Show
          Lukas Rytz added a comment - (In r23673) close SI-3946 . protected in java means access boundary is the package. review by dragos.
          Hide
          Lukas Rytz added a comment -

          (In r23704) follow up on fix SI-3946. relaxed access boundry check for overriding protected java member.

          Show
          Lukas Rytz added a comment - (In r23704) follow up on fix SI-3946 . relaxed access boundry check for overriding protected java member.
          Hide
          Lukas Rytz added a comment -

          By Paul: I find experimentally that javac lets access tighten such that whether
          you can call a method depends on the static type of the argument, which
          would seem like an unfortunate thing to emulate, but possibly not the
          worst thing being considered.

          // J1.java
          package bip;
          
          public class J {
           // package[bip] + protected f()
           protected void f() { }
          }
          
          // J2.java
          package notbip;
          
          public class J2 extends bip.J {
           // this override "should" not be allowed, it excludes package bip
           // now package[notbip] + protected f()
           @Override
           protected void f() { }
          }
          
          // J3.java
          package bip;
          
          public class J3 {
           public void g(bip.J x) {
             x.f();  // ok
             notbip.J2 y = (notbip.J2)x;
             y.f();  // fails
             // J3.java:7: f() has protected access in notbip.J2
             //     y.f();
             //      ^
             // 1 error
           }
          }
          
          Show
          Lukas Rytz added a comment - By Paul: I find experimentally that javac lets access tighten such that whether you can call a method depends on the static type of the argument, which would seem like an unfortunate thing to emulate, but possibly not the worst thing being considered. // J1.java package bip; public class J { // package[bip] + protected f() protected void f() { } } // J2.java package notbip; public class J2 extends bip.J { // this override "should" not be allowed, it excludes package bip // now package[notbip] + protected f() @Override protected void f() { } } // J3.java package bip; public class J3 { public void g(bip.J x) { x.f(); // ok notbip.J2 y = (notbip.J2)x; y.f(); // fails // J3.java:7: f() has protected access in notbip.J2 // y.f(); // ^ // 1 error } }
          Hide
          Lukas Rytz added a comment -

          We discussed this in today's meeting. Martin was surprised how broken
          "protected" in Java is (see Paul's example).

          Summing up. Given the Java class:

          package p;
          public class A {
              protected void f() {}
          }
          

          This indeed means, in Scala terms, "f" is "protected[p]", i.e. we should set
          the "privateWithin" flag to "p". Otherwise, the following Scala code would
          not be legal:

          package p {
            object T {
              val a = new A()
              a.f()
            }
          }
          

          This has been fixed in SI-3946, but with the unfortunate consequence on
          overriding, which invalidates the following (previously valid) Scala code:

          package q {
            class B extends p.A {
              override protected def f() { }
            }
          }
          

          Note that the same situation is much more unlikely to happen in
          Scala-only code, because when one writes "class A" in Scala, writing
          "protected def f", would mean "protected[A]", not "protected[p]".

          We concluded in our discussion that

          • Most Scala programmers are not aware that "protected" in Java actually means accessible in the package ("protected[p]")
          • Changing override rules now would be too confusing, and also invalidate a non-acceptable amount of existing Scala code

          The easiest solution seems to be a special case when checking the
          accessibility of an override. If the overridden symbol is java and protected,
          ignore the "privateWithin".

          Show
          Lukas Rytz added a comment - We discussed this in today's meeting. Martin was surprised how broken "protected" in Java is (see Paul's example). Summing up. Given the Java class: package p; public class A { protected void f() {} } This indeed means, in Scala terms, "f" is "protected [p] ", i.e. we should set the "privateWithin" flag to "p". Otherwise, the following Scala code would not be legal: package p { object T { val a = new A() a.f() } } This has been fixed in SI-3946 , but with the unfortunate consequence on overriding, which invalidates the following (previously valid) Scala code: package q { class B extends p.A { override protected def f() { } } } Note that the same situation is much more unlikely to happen in Scala-only code, because when one writes "class A" in Scala, writing "protected def f", would mean "protected [A] ", not "protected [p] ". We concluded in our discussion that Most Scala programmers are not aware that "protected" in Java actually means accessible in the package ("protected [p] ") Changing override rules now would be too confusing, and also invalidate a non-acceptable amount of existing Scala code The easiest solution seems to be a special case when checking the accessibility of an override. If the overridden symbol is java and protected, ignore the "privateWithin".
          Hide
          Seth Tisue added a comment -

          fwiw, this notorious Scala/Java mixer agrees

          Show
          Seth Tisue added a comment - fwiw, this notorious Scala/Java mixer agrees

            People

            • Assignee:
              Lukas Rytz
              Reporter:
              Lukas Rytz
              TracCC:
              Miles Sabin, Seth Tisue
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development