module-info.class spec and attributes
Peter Kriens
peter.kriens at aqute.biz
Wed Jun 29 02:33:41 PDT 2011
I took a look at the proposal and I have a few comments. But first the picture (cardinalities are allowed by the structure but can be constrained in the text).
There seems to be quite a bit of redundancy (and thus complexity) in this structure because it allows * relations between the flags (provide,require,permit,module) that designate a ModuleId_Info struct. I.e. the proposal allows me to require/permit/provide the same module multiple times. Even though this is not allowed with an extraneous constraint this seems inefficient design, why create the opportunity for errors? It seems that provide/require/permit/module could easily be a handled with an enumeration or bitset: { THIS_MODULE, PROVIDE, PERMIT, REQUIRE_OPTIONAL, REQUIRE_FRAGMENT} in the ModuleId_Info struct? The use of attributes to set a bit seems overkill and will require unnecessary constraints on the cardinality of these attributes, making processing this file in tools harder.
Similar about the redundancy in the module name. The module name is both the this_class package name as well as defined in the ModuleId_Info struct?
Interestingly the model allows package export (though unfortunately not import, one should always wonder why things are not symmetric, but I guess that is another discussion). However, class exports can be top levels only (I assume no nested classes?) and recursively. However, packages are top level classes in the designated package and the all subpackages. This seems to miss the cases for nested classes in the single package and nested classes in the sub-packages?
I am a bit confused about the scope of the module as this is not defined. I.e. a class defines all its members, not just the public ones. Shouldn't a module also define its private members?
Obviously the extension model is a bit of a joke, all we get is a list of unadorned strings per module? The minimum that is needed is a model that allows the exports, provides, permits, and module attributes to be annotated in an elegant way. For example, ModuleClass is clearly a Jigsaw extension and several of the bit fields are also highly semantic, such semantics should be extensible as it is very unlikely you get it right the first time. Why not model these with an extension model and eat your own dog food?
The previous issues were detailed critiques on the design, intended to improve it within the box. However, I believe the premise of using attributes to model modules points to a serious problem with the box. Modularity is hierarchical, a function is modular, a type is modular, a package is modular, and this thing under construction is just the next granular step in modularity.
If a module is modeled as a class (as this design implicitly does by using the class file) then I think it should not introduce a completely new spaghetti ontology based on attributes but instead look at what the class file currently does, as a class is also modular. A class consists of a name, class or interface specific information, imports of other types, members, and conceptually nested types. So what is the member of a module? This is clearly the package. And the member of a package is clearly a Type. As members use other members, types import other types symmetry demands that packages import other packages and modules import other modules (as is done in the proposal with ModuleRequire).
Treating packages as members of a module and imports as references to other modules would make the class file a very good fit; every Java developer would immediately see the symmetry and have an intuitive understanding. Symmetry is one of the most important indicators that you've understood the problem and found the simplest model because it reuses existing concepts on different levels. For example, module extensions could now easily be modeled as standard annotations on members. It would also support module data/methods (static fields/methods in the module), as well as represent the Module Class implicitly.
Falling back to custom class attributes invariably means a huge amount of exceptional cases to handle by the community and makes it surprisingly hard to understand what's going on ...
As the current proposal has no affinity to a class file format whatsoever; it seems wrong to abuse the class file format just because it happens to support attributes. There are better formats for this purpose, formats that could also allow some human readability for debugging and easy annotation by third parties without requiring class format changes for every new module concept. Obviously XML is the most powerful and best suited format for this problem. The JLS module specification can just as easy output to XML as attributes in a class file but will be significantly easier to handle in most environments and will not require an upgrade in class version for every minor change.
Kind regards,
Peter Kriens
On Sat, Jun 25, 2011 at 3:01 AM, Alex Buckley <alex.buckley at oracle.com> wrote:
Since attachments seem to be scrubbed, here is the text of the proposal, obviously without links to the requirements document.
ClassFile changes for Java Modules
Binary form of a module declaration (a.k.a. module-info.class)
A compilation unit that contains a module declaration (and potentially additional arbitrary content) is compiled to a ClassFile structure like any other compilation unit.
By convention, the name of a compilation unit that contains a module declaration is module-info.java, echoing the package-info.java convention for a compilation unit that contains solely a package declaration. Consequently, by convention, the name for the compiled form of a module declaration is module-info.class.
A new flag in the ClassFile.access_flags item, ACC_MODULE (0x0800), indicates that the ClassFile represents a module rather than a class or interface. Note that this flag plays a similar role to ACC_INTERFACE (0x0200), and does not describe accessibility of a class or interface.
If ACC_MODULE is set in ClassFile.access_flags, then no other flag in ClassFile.access_flags may be set, and the following rules apply to the rest of the ClassFile structure:
* major_version, minor_version: >=52.0 (Java SE 8 and above)
* this_class: [Module's name in internal form (JVMS 4.2.1)]/module-info
(Traditionally, if this_class indicates "P/Q/R", then the ClassFile can be expected to live in a file R.class in a directory P/Q representing a package. This explains why "/module-info" is a suffix in this_class above: if this_class indicates "P/Q/module-info", then the ClassFile can be expected to live in a file module-info.class in a directory P/Q representing a module. The "real name" of the module, shorn of "/module-info", can be obtained from the Module attribute.)
* super_class, interfaces_count, fields_count, methods_count: 0
* attributes: One Module attribute must be present, to record the name and version of the module. At most one of each of the ModuleRequires, ModuleProvides, ModulePermits, ModuleExports, ModuleClass, and ModuleData attributes may be present. Except for these attributes and Synthetic, SourceFile, SourceDebugExtension, and Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
The CONSTANT_ModuleId_info structure
The CONSTANT_ModuleId_info structure in the constant pool is used to represent a pair of a module name and a module version.
CONSTANT_ModuleId_info {
u1 tag;
// 19
u2 name_index;
// Points to a CONSTANT_Utf8_info representing module name in internal form (JVMS 4.2.1)
u2 version_index;
// Optionally points to a CONSTANT_Utf8_info representing module version
}
If the version_index item is 0 (as opposed to pointing to a CONSTANT_Utf8_info structure which holds the string "0"), then no module version is present.
If the version_index item is not 0, then a module version is present. There is no required structure or semantics for the underlying UTF8 string which represents a module version.
The Module attribute
Module_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 module_id_index;
}
The items of the Module_attribute structure are as follows:
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "Module".
attribute_length
The value of the attribute_length item must be 2.
module_id_index
The value of the module_id_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_ModuleId_info structure representing the name and version of the module represented by this ClassFile.
The name must be equal to the module name indicated by the ClassFile.this_class item without the "/module-info" suffix.
The ModuleRequires attribute
ModuleRequires_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 requires_length;
{ u2 requires_index; u1 flags; } requires_table[requires_length];
}
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "ModuleRequires".
attribute_length
The value of the attribute_length item is the length of the attribute excluding the initial six bytes.
requires_length
The value of the requires_length indicates the number of entries in the requires_table.
requires_table
Each requires_index must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_ModuleId_info structure representing the target module on which this module depends.
The value of the associated flags item is as follows:
* 0x01 indicates this dependency on the target module is optional.
* 0x02 indictates the target module's types must be loaded by the same defining classloader as the types of the module represented by this ClassFile.
A module name may be referenced by at most one entry in a requires_table.
The ModulePermits attribute
ModulePermits_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 permits_length;
{ u2 permits_index } permits_table[permits_length];
}
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "ModulePermits".
attribute_length
The value of the attribute_length item is the length of the attribute excluding the initial six bytes.
permits_length
The value of the permits_length indicates the number of entries in the permits_table.
permits_table
The value of each permits_index in this item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_ModuleId_info structure representing a module which is permitted to have a dependency on the module represented by this ClassFile.
(It is possible that a module system uses only the name of the permitted module, not its version, in determining visibility.)
A module name may be referenced by at most one entry in a permits_table.
The ModuleProvides attribute
ModuleProvides_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 provides_length;
{ u2 provides_index; } provides_table[provides_length];
}
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "ModuleProvides".
attribute_length
The value of the attribute_length item is the length of the attribute excluding the initial six bytes.
provides_length
The value of the provides_length indicates the number of entries in the provides_table.
provides_table
The value of each provides_index in this item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_ModuleId_info structure representing a module that is an alias for the module represented by this ClassFile.
A module name may be referenced by at most one entry in a provides_table.
The ModuleExports attribute
ModuleExports_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 exports_length;
{ u2 exports_index; u1 export_kind; u2 source_index; } exports_table[exports_length];
}
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "ModuleExports".
attribute_length
The value of the attribute_length item is the length of the attribute excluding the initial six bytes.
exports_length
The value of the exports_length indicates the number of entries in the exports_table.
exports_table
The value of each export_index in this item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing an entity to be exported by the module represented by this ClassFile.
The value of the associated export_kind item indicates the kind of entity to be exported, as follows:
* 0x01 indicates the entity is a class or interface; it is the entity to be exported.
* 0x02 indicates the entity is a class or interface; it and its member types are the entities to be exported.
* 0x04 indicates the entity is a package; the member top-level classes and interfaces (and their member types) of this package are the entities to be exported.
* 0x08 indicates the entity is a package; the member top-level classes and interfaces (and their member types) of this package and all its subpackages (recursively) are the entities to be exported.
The value of the associated source_index item must be a valid index into the constant_pool table where the entry is a CONSTANT_ModuleId_info structure representing the module which declared the exported entity. (In most cases, where the exported entity is declared in the current module, source_index will simply point to the same constant pool entry as the Module attribute. But where the exported entity is re-exported, source_index may assist resolution and diagnostics.)
The ModuleClass attribute
ModuleClass_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 main_class_index;
}
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "ModuleClass".
attribute_length
The value of the attribute_length item is 2.
main_class_index
The value of the main_class_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure representing the name of the class which is the entrypoint to the module represented by this ClassFile.
The ModuleData attribute
ModuleExtension_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 data_index;
}
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "ModuleData".
attribute_length
The value of the attribute_length item is 2.
data_index
The value of the main_class item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the content, other than the module declaration, of the compilation unit that declared the module represented by this ClassFile.
More information about the jigsaw-dev
mailing list