Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "JDT Core/Java9/JLS9"

(Confusion)
(Determining the meaning of a name)
Line 80: Line 80:
 
The last sentence could accommodate the situation that a package Q might contain multiple accessible types named Id, in which case the qualified type name Q.Id cannot be resolved.
 
The last sentence could accommodate the situation that a package Q might contain multiple accessible types named Id, in which case the qualified type name Q.Id cannot be resolved.
 
* Does this mean a name clash (wrt fully qualified names) between two types from different modules should be flagged as a compile error?
 
* Does this mean a name clash (wrt fully qualified names) between two types from different modules should be flagged as a compile error?
 +
** '''If both are accessible: Yes'''
 
* Does this mean a name clash involving one accessible type and one or more inaccessible types is ''not'' an error?
 
* Does this mean a name clash involving one accessible type and one or more inaccessible types is ''not'' an error?
 +
** '''Correct'''
 
* If the latter, does this mean that split packages (across modules) without clashing type names are ''not'' an error?
 
* If the latter, does this mean that split packages (across modules) without clashing type names are ''not'' an error?
 +
** '''Correct'''
 +
{{Tip|Solution|The trick here is, that resolving of a qualified name applies access control: if two types have the same qualified name, but one is not accessible, then it's not a name clash.
 +
}}
 +
;Consequences:The compiler has to distinguish same-named types from different modules.
 +
:* It must detect that these are not compatible
 +
:* It must detect (and allow) when an accessible sub type S of an inaccessible type super type T is passed where the inaccessible type T is required.
 +
:* As a consequence it must be reported as an error if any (inaccessible) type is not available at compile time which is used, e.g., in the signature of a candidate method of any invocation being compiled. To be continued in {{Bug|148844}}.
  
 
The above definitions are also based on visibility of packages and accessibility of types. We already discussed accessibility of types, but how is visibility of packages defined?
 
The above definitions are also based on visibility of packages and accessibility of types. We already discussed accessibility of types, but how is visibility of packages defined?

Revision as of 14:47, 10 January 2017

This page is a working document of attempts to map current drafts of JLS to the semantics as it should be implemented by the compiler.

Sources:

To determine legal program structures a number of concepts must be considered, including:

  • scope
  • visibility
  • importing
  • accessibility
  • observability

Due to lots of cross-references between definitions, it is difficult (impossible?) to introduce and define one concept at a time without already defining all the other concepts.

E.g., scoping and visibility are defined in what looks like a cyclic definition:

  • 6.3: The scope of a declaration is the region of the program within which the entity declared by the declaration can be referred to using a simple name, provided it is visible (§6.4.1).
  • 6.4.1: A declaration d is said to be visible at point p in a program if the scope of d includes p, and d is not shadowed by any other declaration at p.

I.e., scoping depends on visibility and visibility depends on scoping. Let's not worry about this notion of "visibility", it doesn't seem to be relevant for what's new in Java 9.

Terms & Concepts

modular compilation unit
compilation unit containing a ModuleDeclaration
ordinary compilation unit
compilation unit that is not a "modular compilation unit" (7.3)
associated
a compilation unit is said to be "associated" with a module (membership)
  • An observable modular compilation unit is associated with the module that it declares (7.3)
  • For regular compilation units membership in a module is defined by the host system.

Accessibility of a type

Let's try to define the algorithm for determining accessibility of a type.

Start at 6.6.1 Determining Accessibility:

If a top level class or interface type is declared public and is a member of a package that is exported by a module, then the type may be accessed by any code in the same module, and by any code in another module to which the package is exported, provided that the compilation unit in which the type is declared is visible to that other module (§7.3).

so our checklist for cross-module accessibility is

  • type is public
  • containing package is exported by a module
  • referring code location is within another module to which the package is exported
  • compilation unit is visible to the other module

When is a compilation unit visible to a given module?

7.3 Compilation Units

[...] The ordinary compilation units that are visible to M are the observable ordinary compilation units associated with modules read by M. […]

Most of this is determined by "the host system" (i.e., not specified by JLS):

  • observability of a compilation unit (7.3)
  • association of a compilation unit to a module (7.3)

Remains: source and target modules have a reads connection.

The host system must use the Java Platform Module System to determine which modules are read by M (§7.7.1).

7.7.1 is still empty as of 2016-12-16

Dealing with ambiguous names

Let's now try to find out how a compiler is supposed to handle ambiguous names, in particular with regard to package names and qualified type names, possibly referring to elements from different modules.

Determining the meaning of a name

Let's assume that this question will be answered in section 6.5 ("Determining the meaning of a name").

6.5.3.2 Qualified Package Names
If a package name is of the form Q.Id, then Q must also be a package name. The package name Q.Id names a package that is the member named Id within the package named by Q.
If Q.Id does not name a package visible to the current module, then a compile-time error occurs.

Nothing hints at the possibility for multiple packages of the same name (per module), so if two modules would try to declare the same package we should probably consider this as one split package. This is also in line with this sentence:

6.4.1 Shadowing
[...] A package declaration never shadows any other declaration.

implying that in particular a package from one module cannot shadow a same-named package from another module.

From hear-say we know that split packages should be banned from Java 9, but where would this be defined and what kind of error should be signalled?

6.5.5.2 Qualified Type Names
If a type name is of the form Q.Id, then Q must be either a type name or a package name.
If a type name is of the form Q.Id, then Q must be either the name of a visible type or the name of a visible package.
If Id names exactly one accessible type (§6.6) that is a member of the type or package denoted by Q, then the qualified type name denotes that type.

The last sentence could accommodate the situation that a package Q might contain multiple accessible types named Id, in which case the qualified type name Q.Id cannot be resolved.

  • Does this mean a name clash (wrt fully qualified names) between two types from different modules should be flagged as a compile error?
    • If both are accessible: Yes
  • Does this mean a name clash involving one accessible type and one or more inaccessible types is not an error?
    • Correct
  • If the latter, does this mean that split packages (across modules) without clashing type names are not an error?
    • Correct
Idea.png
Solution
The trick here is, that resolving of a qualified name applies access control: if two types have the same qualified name, but one is not accessible, then it's not a name clash.
Consequences
The compiler has to distinguish same-named types from different modules.
  • It must detect that these are not compatible
  • It must detect (and allow) when an accessible sub type S of an inaccessible type super type T is passed where the inaccessible type T is required.
  • As a consequence it must be reported as an error if any (inaccessible) type is not available at compile time which is used, e.g., in the signature of a candidate method of any invocation being compiled. To be continued in bug 148844.

The above definitions are also based on visibility of packages and accessibility of types. We already discussed accessibility of types, but how is visibility of packages defined?

When speaking of "visible", the JLS text typically refers to 6.4.1 (Shadowing), with the following exception:

6.3 Scope of a declaration
[...] The scope of the declaration of an observable top level package (§7.4.3) is all observable compilation units associated with modules to which the package is visible (§7.3).

Hence, visibility of packages should be defined in 7.3.

7.3 Compilation Units
[...] The ordinary compilation units that are visible to M are the observable ordinary compilation units associated with modules read by M. The host system must use the Java Platform Module System to determine which modules are read by M (§7.7.1).
The ordinary compilation units that are visible to M drive the packages that are visible to M (§7.4.3), which in turn drives the top level packages in scope for code in compilation units associated with M (§6.3).

The first sentence was already discussed above. What's new is the fact that a package p is visible to M if any compilation unit declaring the package p is visible to M.

Ergo, in the hypothetical case that multiple modules declare types in the same package p, p will be visible to M if only one type from a module M1 is visible to M, disregarding the possibility that M2 may define more types in p, which may be invisible to M.

Let's look into the section referenced from 7.3:

7.4.3 Observability of a Package
A package is visible to a module if and only if an ordinary compilation unit containing a declaration of the package is visible to the module.

Yep, no contradiction to my hypothesis.

Imports

7.5.1 Single-Type-Import Declarations
The TypeName must be the canonical name of a class type, interface type, enum type, or annotation type (§6.7).

Similar in 7.5.2 (Type-Import-on-Demand Declarations). Compile errors are specified only in terms of visibility and accessibility. => This doesn't seem to require detection of ambiguity / duplicate types.

Questions

Package Names

Does JLS

  • prevent split packages, or
  • handle ambiguity of package names (ambiguous membership of a package in several modules)?

File System Organization

7 Packages and Modules
Modules and packages may be stored in a file system or in a database (§7.2). Modules and packages that are stored in a file system may have certain constraints on the organization of their compilation units to allow a simple implementation to find module and type declarations easily.
7.3 Compilation Units
The host system also determines which observable ordinary compilation units are associated with a module, except for ...
  • Does JLS provide any help in coordinating "constraints" between implementations?

JPMS

7.3 Compilation Units
The host system must use the Java Platform Module System to determine which modules are read by M (§7.7.1).
  • What is the JPMS? Is it section 7.7 (no mention of "read" in draft for 7.7)? Is it an extra document?

Task

Check JDT implementation

  • Section 6.5.3 does not mandate a compile-time error if no module with that name is observable. This is because exports and opens statements in a module declaration are tolerant of non-existent module names, while the requires statement in a module declaration performs its own validation of the module name given as its operand.
Does JDT implement this tolerance?

Critique

Confusion

Also the term "observability" comes in different flavors, as 7.4.3 introduces a distinction between "'technically' observable" and "'really' observable". I believe this distinction only works around the legacy that packages are defined to span a containment tree (packages as members of other packages), whereas JPMS wants to regard all packages as independent, disregarding "containment" / "membership".

Watch out: Alex may be introducing another overload of "hiding", to affect types from another module that are visible but "hidden" by a type in the current module.

Back to the top