[jsr294-modularity-eg] dependency declaration syntax...
Bryan Atsatt
bryan.atsatt at oracle.com
Thu May 14 16:56:31 EDT 2009
I suggested on yesterday's call that the extensibility model ought to be
structured such that the declarations look just like the standardized
ones. This, in theory, allows us to standardize in the future elements
that we consider 'extensions' today.
In playing with this idea, I ended up with a very simple, very generic
model. First, treat all declarations uniformly as a 'keyword' followed
by a list of ' ' separated strings, so:
requires module m:1.1 local;
requires module n:1.0 vendor=Sun optional;
permits foo:1.0;
permits bar vendor=Sun;
classpath a.jar b.jar c.jar;
can all be accessed via the same raw/low-level collection semantics:
Set<List<String>> get(String keyWord);
Calling info.get("requires") would return:
{"module", "m:1.1", "local"}
{"module", "n:1.0", "vendor=Sun", "optional"}
and info.get("permits") would return:
{"foo:1.0"}
{"bar ", "vendor=Sun"}
and info.get("classpath") would return:
{"a.jar", "b.jar", "c.jar"}
Now, as we agree on structure for a 'keyword', we standardize the
grammar and add convenience methods to access the data in a more
structured fashion. And we do so now for 'requires'/'provides' (or
'imports'/'exports' if we like that better). So we end up with api like:
Set<Contract> getImports();
Set<Contract> getExports();
that are layered on top of the low-level access api:
Set<List<String>> get(String keyWord);
While hardly perfect, this model seems like a reasonable compromise
between the no-extensibility position that we started with, and the
fully-extensible-type-safe-but-new-language-feature (:^) position Bob
proposed.
// Bryan
Bryan Atsatt wrote:
> Alex Buckley wrote:
>> Regarding #3 and #4, it's hard to imagine a dependency which doesn't
>> have a target (name and optionally version). If granularity
>> conventionally gets its own term, the target should too:
>>
>> requires package bar @ [1.0,2.0) flag1 k="v" flag2 ;
>>
>> 'requires' ID ID ['@' VER] ( ID ['=' '"' ID '"'] )* ';'
> Yes, pulling the target out makes sense to me as well. (I'm not
> convinced that version should be optional, but that is a different
> discussion).
>>
>> To validate the ID/VER terms, a compiler passes them to an API along
>> the lines of
>> http://cr.openjdk.java.net/~mr/jigsaw/api/java/lang/module/ModuleSystem.html
>>
> Absolutely; the compiler must use something like this abstraction to
> both validate *and* resolve the declarations to actual module instances.
>
>
> I think we also need to consider an extension mechanism that will
> allow additional metadata to be introduced without updating the JLS.
> We've run around in circles about 'permits' and 'classpath', etc,
> so... we probably do need to open this space up. (Bob, I realize that
> your proposal certainly does this, but I'd like to also explore the
> simple end of the spectrum--given that a module system MUST be
> involved in validation/resolution, I don't see that we need the
> compiler to do any type checking).
>
> I prefer to think about this problem by exploring how the grammar
> might be reified. So here's a stab at it, using 'imports'/'exports'
> instead of 'requires'/'provides':
>
> public interface Identifier {
> public String getName();
> public String getVersion();
> }
>
> public interface AttributeContainer {
> public boolean hasAttribute(String name);
> public String getAttribute(String name);
> public Set<String> getAttributeNames();
> }
>
> public interface Contract extends AttributeContainer {
> public String getScope(); // e.g. "package", "module",
> "service", etc.
> public Identifier getTarget();
> }
>
> public class ModuleInfo implements Identifier, AttributeContainer {
>
> // Single common parsing method
> public static ModuleInfo define(byte[] moduleInfo) {...}
>
> // Module system
> public Identifier getModuleSystem() {...};
>
> // Module name and version
> public String getName() {...};
> public String getVersion() {...};
>
> // Dependencies
> public Set<Contract> getImports() {...};
> public Set<Contract> getExports() {...};
>
> // Generic metadata
> public boolean hasAttribute(String name) {...};
> public String getAttribute(String name) {...};
> public Set<String> getAttributeNames() {...};
> }
>
> In this simple model, 'permits' and 'classpath' or any other such
> constructs have to be represented as attribute strings. So (switching
> from '@' to ':' for the version separator):
>
> module ID ':' VER {
> 'system' ID ':' VER ';'
> 'imports' ID ID [':' VER] ( ID ['=' '"' ID '"'] )* ';'
> 'exports' ID ID [':' VER] ( ID ['=' '"' ID '"'] )* ';'
> ( ID '=' '"' ID '"' ';' )*
> }
>
> module M : 5.0 {
> system jigsaw:1.0;
> imports module P:2.0 local vendor="acme";
> imports module N:1.0+ optional;
> exports module M:4.5+; // M v5.0 is compatible with 4.5+
> permits = "module O"; // Module O is M's friend
> }
>
> module M : 5.0 {
> system osgi:3.2;
> imports package P:(1.0,2.0];
> imports module N:1.0 optional;
> exports package m;
> classpath="jar1, jar2";
> }
>
> // Bryan
>>
>> Alex
>>
>> Bryan Atsatt wrote:
>>> We have now discussed a number of options for keyword (requires,
>>> provides, etc.) operand syntax:
>>>
>>> requires <operand>;
>>>
>>> I thought I'd try to enumerate the options so far...
>>>
>>> 1. Opaque string:
>>>
>>> requires foo at 1.3;
>>>
>>> 2. Granularity + opaque string:
>>>
>>> requires module foo at 1.3;
>>>
>>> 3. Granularity + unbounded key/value strings:
>>>
>>> requires package name=bar, version=1.1, vendor=acme;
>>>
>>> 4. Granularity + bounded, typed key/value pairs (annotation using
>>> lowercase and without leading "@"):
>>>
>>> requires package(name=bar, version=1.1); // Really @package.
>>>
>>>
>>> (We also discussed an "unbounded, typed key/value pairs" variant,
>>> re-using just the annotation style syntax, but... Without a type
>>> declaration mechanism, we would be in the inference business; I
>>> don't think we want/need to take that step).
>>>
>>>
>>> For each operand type, we need to consider how it would be reified
>>> in a ModuleInfo class. I expect that for each keyword, we will need
>>> a method that returns a Set<T>, where T is the operand type, e.g.
>>>
>>> public Set<String> getRequires();
>>>
>>> for the opaque string case (1). For cases 2 and 3, we would need to
>>> create a new descriptor type to wrap the granularity and the string
>>> or key/value strings. Case 4 seems to require a return type of
>>> Object, necessitating a downcast.
>>>
>>>
>>> I believe one constraint on the design space here is that a
>>> key/value syntax needs to be unbounded: OSGi supports arbitrary
>>> attributes on dependency declarations. This would imply a hack in
>>> the annotations case (e.g. name=bar, version=1.1,
>>> attributes="key1=value1, ...").
>>>
>>> And while I do like the idea that annotations provide an easily
>>> consumed grammar, the extra complexity here does not seem worth it
>>> (even aside from Alex's concerns about compiler difficulties).
>>>
>>> So far, I think 3 provides the best balance of
>>> functionality/clarity/simplicity/extensibility.
>>>
>>> // Bryan
>>>
>>> _______________________________________________
>>> jsr294-modularity-eg mailing list
>>> jsr294-modularity-eg at cs.oswego.edu
>>> http://cs.oswego.edu/mailman/listinfo/jsr294-modularity-eg
>> _______________________________________________
>> jsr294-modularity-eg mailing list
>> jsr294-modularity-eg at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/jsr294-modularity-eg
>>
> _______________________________________________
> jsr294-modularity-eg mailing list
> jsr294-modularity-eg at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/jsr294-modularity-eg
>
More information about the jsr294-modularity-eg
mailing list