On 29.04.2017 01:25, Alex Buckley wrote:
On 4/27/2017 12:38 PM, Stephan Herrmann wrote:
For illustration:

(A) Is JPMS a module system that keeps the semantics of qualified names as
they are in Java 8 and only superimposes encapsulation boundaries?
(i.e., each type is globally uniquely identified by its qualified name).

(B) Is JPMS a module system that maintains the assumption that from the
perspective of each module all relevant types can be distinguished using
their qualified name?
(i.e. admitting identical qualified names as long as no compilation of one
module will ever encounter several candidates at once).

(C) Is JPMS a module system that establishes a separate namespace for each
module, where types with identical qualified name - but defined in
different modules - need to be distinguished?
(i.e., uniqueness is primarily required for module-prefixed qualified
names).

Despite some efforts I fail to find a definite answer in JLS (and Alex
mentioned that some of this is still being discussed). Still JLS as of
today sounds mostly like (A). To me (B) sounds like the natural choice, but I
understood Alex as saying it *should* be (C). I don't see, however, how the
conceptual framework of JLS could possibly support such design.

(B) and (C) are not mutually exclusive because (B) was worded from the 
perspective of each module while (C) was not.

(B) is true.

No. (B) may be true for your example, but it is not for the following
(which is similar to examples we had in our January thread):


//-- M/module-info.java
module M { exports pm; }

//-- M/impl/Other.java
package impl;
public class Other { }

//-- M/pm/C1.java
package pm;
import impl.Other;
public class C1 extends Other {
        public void m1(Other o) {}
}
//--
//-- O/module-info.java
module O { requires M; }

//-- O/impl/Other.java
package impl;
public class Other { }

//-- O/po/Client.java
package po;
import pm.C1;
public class Client {
        void test1(C1 one) {
                one.m1(one);
        }
}
//--

Looking at O, and trying to determine whether the method invocation one.m1(one)
is legal, M's type impl.Other is *relevant*, because analysis must ...
- detect that the type reference "Other" in the signature of m1 refers to the
  type defined in M, not to the same-named type in O.
- similarly detect that the type reference in C1's class header (or superclass
  classfile attribute) refers to M's impl.Other.
- conclude from the above, that C1 is compatible to m1's parameter.

Ergo, the set of types relevant from the perspective of O contains two
same-named types.


If Java 9 permits this situation, it not only hugely increases the complexity
of all tools that need to "understand" this program, it also wastes a unique
opportunity that JPMS has, which existing module systems did not have:

Java 9 could make "API leaks" either illegal or ineffective and thus rule out
an entire category of ill-formed programs, which to-date must unfortunately
be accepted by module-unaware compilers:

  (A) Java 9 has the opportunity to say that the declaration of m1 is illegal,
  because it publicly exposes a non-accessible type, which is broken in
  every regard.

  (B) Alternatively, Java 9 has the opportunity to say that any attempt to
  invoke m1 from outside M is illegal, because clients would need to know
  about an inaccessible type.


For comparison note, that the following is already illegal:


//-- M/module-info.java
module M { exports pm; }

//-- M/impl/Func.java
package impl;
public interface Func {
        void show(Object o);
}

//-- M/pm/C1.java
package pm;
import impl.Func;
public class C1 {
        public void m2(Func f) {}
}
//--
//-- O/module-info.java
module O { requires M; }

//-- O/po/Client.java
package po;
import pm.C1;
public class Client {
        void test2(C1 one) {
                one.m2(a -> {}); // javac: error: Func is not visible
        }
}
//--

Interestingly, Client is now rejected due to an attempt to "implicitly
access" an inaccessible type, which is backed by 15.27.3 saying:
  "It is a compile-time error if any class or interface mentioned by either
   U or the function type of U is not accessible (ยง6.6) from the class or
   interface in which the lambda expression appears."

The same reasoning should also apply to the attempt to invoke m1 above.

Otherwise, add type inference to the mix, and open a can of inconsistencies,
giving abundant material for lots of confused discussions on StackOverflow.

Stephan

Reply via email to