From john.r.rose at oracle.com Tue Mar 22 20:21:21 2016 From: john.r.rose at oracle.com (John Rose) Date: Tue, 22 Mar 2016 13:21:21 -0700 Subject: Model 3 classfile design document In-Reply-To: <201602112224.u1BMOcBp005571@d01av01.pok.ibm.com> References: <56A25E41.6040508@oracle.com> <201602112224.u1BMOcBp005571@d01av01.pok.ibm.com> Message-ID: The full display of type variables, with all their definition sites, strikes me as clunky, from a VM perspective. It's a large amount of AST info. For inner classes, we flatten up level references by introducing synthetic variables and fields. In a few places core reflection needs an attribute to map backward but the executable part is all flattened. This makes it easier to execute and compile. Could we do a similar trick for type variables? I.e. represent up-level type vars as a flat sequence of synthetic local copies. ? John > On Feb 11, 2016, at 2:24 PM, Bjorn B Vardal wrote: > > where Inner doesn't declare any type variables, my understanding is that Inner will still have the GenericClass attribute because it may refer to T. Will Inner still appear as the first class frame, with tvarCount=0, enforcing the rule that the first element is always the class itself? From brian.goetz at oracle.com Thu Mar 24 21:47:17 2016 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 24 Mar 2016 17:47:17 -0400 Subject: ParameterizedType encoding (was: Model 3 classfile design document) In-Reply-To: References: <56A25E41.6040508@oracle.com> <201602112224.u1BMOcBp005571@d01av01.pok.ibm.com> Message-ID: <56F46065.3000904@oracle.com> The complex structure you refer to exists in two places: - The GenericClass attribute, which describes the structure of the type variables; - The ParameterizedType attribute, through its 'enclosing' field. The structure of these two need to line up, which opens up various sorts of possibility for error, which must be checked at runtime. So, why did I propose this, and not just flattening the tvars into a linear array? The proposed form is derived from some (presumed) compatibility requirements. These leak in because, even though Outer and Inner are derived from the same source file (and presumably therefore their classfiles will always be consistent), *other* classfiles can describe Outer.Inner using ParamType, and its possible that Outer/Inner can be modified without recompiling the client. Let's make these compatibility requirements more explicit. In the absence of qualification, "compatible" means "binary and source compatible for clients and subclasses." 1. Renaming a type variable should be compatible. The rationale here is, the choice of parameter names is an implementation detail, and its reasonable to treat the choice of type variable names the same way. We accomplish this by encoding type variable uses with indexes instead of names -- but this depends on the stability of indexes. 2. (Non-requirement.) We don't require that reordering or removing type variables be compatible. While it would be nice if we could do this, the number and order of type variables is part of a classes interface definition. A Map is a map from K to V; the order is fixed when we first publish the class. Note that (1) and (2) match the story for method argument lists today; you can compatibly rename parameters, but not remove or reorder them. (See below for adding.) 3. Anyfying an existing erased type variable should be compatible; I should be able to evolve class Foo to be class Foo. The rationale is obvious; if this were not the case, we couldn't anyfy any of our existing libraries. So far, nothing too controversial. Now, let's move on to some "would be nice" evolution cases. 4. Generifying a non-generic class by adding one or more erased type variables should be (at least binary) compatible. This means that if we have Outer.Inner, it would be nice if we could evolve this to Outer.Inner. And similarly, if we have Outer.Inner, it would be nice if we could evolve this to be Outer.Inner. (Note that #4 + #3 means we can also add any-tvars too.) This is the case with existing erased generics; so long as we follow some rules, we can generify existing classes without breaking clients. But, adding type variables somewhere in the chain has the potential to perturb the numbering scheme for type variables, conflicting with #1 above. Note that whether we start numbering outer-to-inner, or inner-to-outer, a continuous numbering system will be perturbed by one of the above scenarios. 5. (Weak requirement.) It would be nice if adding new erased type variables to the end of the type variable argument list were also binary compatible, as it is today with erased generics. This also has the potential to perturb continuous numbering schemes. Given these requirements, gleaned from existing compatibility behaviors, nudged us in the direction of explicitly modeling Outer.Inner as a chain of parameterized type descriptors, rather than one flattened descriptor. When we encounter a PT, we match its structure (loosely, to account for #4 and #5) to the GenericClass descriptor for the described template class, as well as validating type parameters (e.g., that we haven't passed "I" to an erased type parameter.) Alternately, we could have encoded type variables as (owner, index within owner) pairs. But, even with such an encoding, we would have to go through a similar validation process as above; this changes the representation, but not the amount of work. Alternately alternately, we could encode a snapshot of the as-of-compile-time contents of the GenericClass, so that separate compilation changes can be detected and possibly corrected. But this seems overkill. On 3/22/2016 4:21 PM, John Rose wrote: > The full display of type variables, with all their definition sites, strikes me as clunky, from a VM perspective. It's a large amount of AST info. > > For inner classes, we flatten up level references by introducing synthetic variables and fields. In a few places core reflection needs an attribute to map backward but the executable part is all flattened. This makes it easier to execute and compile. > > Could we do a similar trick for type variables? I.e. represent up-level type vars as a flat sequence of synthetic local copies. > > ? John > >> On Feb 11, 2016, at 2:24 PM, Bjorn B Vardal wrote: >> >> where Inner doesn't declare any type variables, my understanding is that Inner will still have the GenericClass attribute because it may refer to T. Will Inner still appear as the first class frame, with tvarCount=0, enforcing the rule that the first element is always the class itself? From brian.goetz at oracle.com Thu Mar 24 22:00:26 2016 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 24 Mar 2016 18:00:26 -0400 Subject: Classes, specializations, and statics In-Reply-To: <201603182102.u2IL2Hk5027593@d03av02.boulder.ibm.com> References: <1395529931.1029351.1456257415180.JavaMail.zimbra@u-pem.fr> <201602222111.u1MLBcpn021902@d03av01.boulder.ibm.com> <56CBA674.9030301@oracle.com> <201603182102.u2IL2Hk5027593@d03av02.boulder.ibm.com> Message-ID: <56F4637A.4020600@oracle.com> I think there's two ways to think about "specialized statics" at the VM level; how you think about it conditions which way you're inclined to go. Way 1: This is a new thing; we used to have placements for "static" and "instance", and now we have three placements: static, instance, and specialization. We add a new bit (ACC_SPECIES), and define new bytecode behaviors for members with the SPECIES bit set. Way 2: There's still only two placements, static and instance; per-specialization static is just the natural reinterpretation of "static" in the face of a many-to-one relationship between source classes and runtime classes. What we used to think of static really is the weird case, which we can model as "new static, but restricted (using "where" restriction) to the all-erased specialization." Both ways are 100% compatible with existing generic sources and classfiles. Way 2 (which seems more natural to me, and also means we don't have to invent a new thing at the VM level) exploits the requirement that Constant_Class[Foo] and Constant_ParamType[Foo, erased] *must* describe the same runtime entity. With Way 2, we still (probably) have a new concept at the language level, which governs whether the so-described member is a member of all parameterizations, or only the all-erased one, but this gets compiled away. This matches up with our treatment of erasure; it is the choice of the language compiler to choose erased generics or reified, and Java chooses to erase some parameterizations but not all. .NET chooses Way 2 in the extreme; static members are not shared across specializations at all, since they have no notion of erasure. Compatibility wouldn't let us go that far; existing statics are shared across all erased parameterizations, so they would need to remain so. On 3/18/2016 5:01 PM, Bjorn B Vardal wrote: > > I wonder if it's not better to have a class like ThreadLocal or > ClassValue that > > represents a constant that can be different depending on the > specialization. > That solution seems possible - we could implement > specialization-specific statics as a static Map, Foo>, > where the type parameter is the key and "specialized static" is the > value. However, it would be slower than compiling to static access. > Are there other use cases that make specialized statics necessary? So > far we have empty collection, which can be implemented using the map. > State of the Specialization from Dec 2014 mentioned layers - are > specialized statics a step along the path to layers? Will a > SpecializedValue map for specialized statics look like an > afterthought if we go the rest of the way to layers? > -- > Bj?rn V?rdal > > ----- Original message ----- > From: Remi Forax > To: Valhalla Expert Group Observers > > Cc: Bjorn B Vardal/Ottawa/IBM at IBMCA, Brian Goetz > > Subject: Re: Classes, specializations, and statics > Date: Tue, Feb 23, 2016 2:57 PM > I wonder if it's not better to have a class like ThreadLocal or > ClassValue that represents a constant that can be different > depending on the specialization. > > R?mi > > ----- Mail original ----- > > De: "Brian Goetz" > > ?: "Bjorn B Vardal" > > Cc: valhalla-spec-experts at openjdk.java.net > > Envoy?: Mardi 23 F?vrier 2016 01:23:16 > > Objet: Re: Classes, specializations, and statics > > > > It's possible that there could be multiple "ssinit" methods, each > > restricted to specific parameterizations (just like any other > restricted > > method), but in general, the "ssinit" method can be specialized just > > like any other method. So what I envision (in the absence of > > initialization of conditional members) is possibly two such > methods; one > > that is specializable (corresponding to _SS members) and one that is > > not, restricted to the erased parameterization (corresponding to > > traditional statics.) > > > > > > > > On 2/22/2016 4:11 PM, Bjorn B Vardal wrote: > > > I think we're on the same page regarding specialized . > > > - The JVM will be handed multiple partial methods, > and the > > > specializer will take care of selecting the appropriate > for > > > each specialization. > > > - The erased will contain the non-specialized static > > > initialization code, which ensures that it only runs once. > > > - The erased will always run before the first > specialization > > > . > > > - The Java syntax is still up for discussion. > > > > I think this is mostly a matter of coming up with the right > syntax, > > > which makes it clear that statics can be per-class or > > > per-specialization. There are a whole pile of related > > > specialization-related syntax issues, I'll try to get them all > in one > > > place. > > > I don't think the problem will be to make it clear that > statics can be > > > per-class or per-specialization, but rather why some > parameterizations > > > (which to the user are synonymous with specializations) don't > appear > > > to have specialized statics. Do we want to put erasure in the > face of > > > users like this? It seems better to let the users deal purely with > > > parameterizations, and we let specialization and erasure be > > > implementation details. > > > -- > > > Bj?rn V?rdal > > > > > > ----- Original message ----- > > > From: Brian Goetz > > > To: Bjorn B Vardal/Ottawa/IBM at IBMCA, > > > valhalla-spec-experts at openjdk.java.net > > > Cc: > > > Subject: Re: Classes, specializations, and statics > > > Date: Thu, Feb 18, 2016 7:55 PM > > > > > > > > >> Based on the example above, I think we need to be more > explicit > > >> about how the method is handled. > > >> There are really two different sets of statics that need > to be > > >> handled by the class initialization: > > >> A) common statics (shared across all instantiations) > > >> B) specialized statics > > >> In addition to the statics, there is also common (and maybe > > >> specialized?) code that is run as part of . > > > > > > There is a reasonable model to collapse these back into one > > > concept; treat "common statics" as specialized statics on the > > > all-erased parameterization, with a clause that > restricts > > > them to that parameterization. Not clear whether we > actually want > > > to represent it that way or not, but its a useful mental model > > > that doesn't require the creation of a third thing. (Since > > > Class[Foo] and ParamType[Foo,erased*] describe the same class, > > > this is also fully binary compatible with existing classes.) > > > > > > Which means we can do a similar thing with , if we > want. > > > I'll wave my hands because we've not yet talked much about > > > conditional members, but it basically looks like this: > > > > > > > > > () { /* common static init code */ > > > /* specializable init code */ } > > > > > > () { /* specializable init code */ } > > > > > > Or not. > > >> Where will the initialization code for both kinds of > statics be? > > >> The existing method? > > > > > > We have two choices: > > > - have a new block that gets run once per > > > specialization, and keep > > > - merge the two as above, exploiting planned support for > > > conditional members > > > > > > Either way, as you say, we have to ensure that the common init > > > runs exactly once. > > >> When using *static, are we only discussing {get,put}? Or > is this > > >> also proposing invokestatic changes to allow specialized > static > > >> methods? > > > > > > Methods too. > > >> All of the technical details aside, is this something we > really > > >> want to expose to the users? They're going to have a > hard time > > >> understanding why Foo (or Foo specialized > > >> statics while Foo & Foo share the erased > version. > > > > > > I think this is mostly a matter of coming up with the right > > > syntax, which makes it clear that statics can be per-class or > > > per-specialization. There are a whole pile of related > > > specialization-related syntax issues, I'll try to get them > all in > > > one place. > > > > > > > > > > > > From forax at univ-mlv.fr Thu Mar 24 23:01:02 2016 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 25 Mar 2016 00:01:02 +0100 (CET) Subject: Classes, specializations, and statics In-Reply-To: <56F4637A.4020600@oracle.com> References: <1395529931.1029351.1456257415180.JavaMail.zimbra@u-pem.fr> <201602222111.u1MLBcpn021902@d03av01.boulder.ibm.com> <56CBA674.9030301@oracle.com> <201603182102.u2IL2Hk5027593@d03av02.boulder.ibm.com> <56F4637A.4020600@oracle.com> Message-ID: <1230675344.35291.1458860462924.JavaMail.zimbra@u-pem.fr> Hi Brian, you forget Way 3 :) Way 3: There's still only two placements, static and instance; "static" means independent of an instance as before, thus i can not be specialized by a type parameter (which is specific to an instance). Unlike Way 2, static means static and unlike Way 1, there is no need to a new placement, ACC_SPECIES, because there is a new data-structure let's call it TypeValue that allows to create a map which is indexed by a reified type parameter. class Collections { private static final TypeValue> EMPTY_LIST = new TypeValue<>() { public List<*> create(Type type) { return EmptyList.class.newSpecializedInstance(type); } }); public static List emptyList() { return (List)TYPE_VALUE.get(T.class); } } regards, R?mi ----- Mail original ----- > De: "Brian Goetz" > ?: "Bjorn B Vardal" , valhalla-spec-experts at openjdk.java.net > Envoy?: Jeudi 24 Mars 2016 23:00:26 > Objet: Re: Classes, specializations, and statics > > I think there's two ways to think about "specialized statics" at the VM > level; how you think about it conditions which way you're inclined to go. > > Way 1: This is a new thing; we used to have placements for "static" and > "instance", and now we have three placements: static, instance, and > specialization. We add a new bit (ACC_SPECIES), and define new bytecode > behaviors for members with the SPECIES bit set. > > Way 2: There's still only two placements, static and instance; > per-specialization static is just the natural reinterpretation of > "static" in the face of a many-to-one relationship between source > classes and runtime classes. What we used to think of static really is > the weird case, which we can model as "new static, but restricted (using > "where" restriction) to the all-erased specialization." > > Both ways are 100% compatible with existing generic sources and > classfiles. Way 2 (which seems more natural to me, and also means we > don't have to invent a new thing at the VM level) exploits the > requirement that Constant_Class[Foo] and Constant_ParamType[Foo, erased] > *must* describe the same runtime entity. > > With Way 2, we still (probably) have a new concept at the language > level, which governs whether the so-described member is a member of all > parameterizations, or only the all-erased one, but this gets compiled > away. This matches up with our treatment of erasure; it is the choice > of the language compiler to choose erased generics or reified, and Java > chooses to erase some parameterizations but not all. > > .NET chooses Way 2 in the extreme; static members are not shared across > specializations at all, since they have no notion of erasure. > Compatibility wouldn't let us go that far; existing statics are shared > across all erased parameterizations, so they would need to remain so. > > On 3/18/2016 5:01 PM, Bjorn B Vardal wrote: > > > I wonder if it's not better to have a class like ThreadLocal or > > ClassValue that > > > represents a constant that can be different depending on the > > specialization. > > That solution seems possible - we could implement > > specialization-specific statics as a static Map, Foo>, > > where the type parameter is the key and "specialized static" is the > > value. However, it would be slower than compiling to static access. > > Are there other use cases that make specialized statics necessary? So > > far we have empty collection, which can be implemented using the map. > > State of the Specialization from Dec 2014 mentioned layers - are > > specialized statics a step along the path to layers? Will a > > SpecializedValue map for specialized statics look like an > > afterthought if we go the rest of the way to layers? > > -- > > Bj?rn V?rdal > > > > ----- Original message ----- > > From: Remi Forax > > To: Valhalla Expert Group Observers > > > > Cc: Bjorn B Vardal/Ottawa/IBM at IBMCA, Brian Goetz > > > > Subject: Re: Classes, specializations, and statics > > Date: Tue, Feb 23, 2016 2:57 PM > > I wonder if it's not better to have a class like ThreadLocal or > > ClassValue that represents a constant that can be different > > depending on the specialization. > > > > R?mi > > > > ----- Mail original ----- > > > De: "Brian Goetz" > > > ?: "Bjorn B Vardal" > > > Cc: valhalla-spec-experts at openjdk.java.net > > > Envoy?: Mardi 23 F?vrier 2016 01:23:16 > > > Objet: Re: Classes, specializations, and statics > > > > > > It's possible that there could be multiple "ssinit" methods, each > > > restricted to specific parameterizations (just like any other > > restricted > > > method), but in general, the "ssinit" method can be specialized just > > > like any other method. So what I envision (in the absence of > > > initialization of conditional members) is possibly two such > > methods; one > > > that is specializable (corresponding to _SS members) and one that is > > > not, restricted to the erased parameterization (corresponding to > > > traditional statics.) > > > > > > > > > > > > On 2/22/2016 4:11 PM, Bjorn B Vardal wrote: > > > > I think we're on the same page regarding specialized . > > > > - The JVM will be handed multiple partial methods, > > and the > > > > specializer will take care of selecting the appropriate > > for > > > > each specialization. > > > > - The erased will contain the non-specialized static > > > > initialization code, which ensures that it only runs once. > > > > - The erased will always run before the first > > specialization > > > > . > > > > - The Java syntax is still up for discussion. > > > > > I think this is mostly a matter of coming up with the right > > syntax, > > > > which makes it clear that statics can be per-class or > > > > per-specialization. There are a whole pile of related > > > > specialization-related syntax issues, I'll try to get them all > > in one > > > > place. > > > > I don't think the problem will be to make it clear that > > statics can be > > > > per-class or per-specialization, but rather why some > > parameterizations > > > > (which to the user are synonymous with specializations) don't > > appear > > > > to have specialized statics. Do we want to put erasure in the > > face of > > > > users like this? It seems better to let the users deal purely with > > > > parameterizations, and we let specialization and erasure be > > > > implementation details. > > > > -- > > > > Bj?rn V?rdal > > > > > > > > ----- Original message ----- > > > > From: Brian Goetz > > > > To: Bjorn B Vardal/Ottawa/IBM at IBMCA, > > > > valhalla-spec-experts at openjdk.java.net > > > > Cc: > > > > Subject: Re: Classes, specializations, and statics > > > > Date: Thu, Feb 18, 2016 7:55 PM > > > > > > > > > > > >> Based on the example above, I think we need to be more > > explicit > > > >> about how the method is handled. > > > >> There are really two different sets of statics that need > > to be > > > >> handled by the class initialization: > > > >> A) common statics (shared across all instantiations) > > > >> B) specialized statics > > > >> In addition to the statics, there is also common (and maybe > > > >> specialized?) code that is run as part of . > > > > > > > > There is a reasonable model to collapse these back into one > > > > concept; treat "common statics" as specialized statics on the > > > > all-erased parameterization, with a clause that > > restricts > > > > them to that parameterization. Not clear whether we > > actually want > > > > to represent it that way or not, but its a useful mental model > > > > that doesn't require the creation of a third thing. (Since > > > > Class[Foo] and ParamType[Foo,erased*] describe the same class, > > > > this is also fully binary compatible with existing classes.) > > > > > > > > Which means we can do a similar thing with , if we > > want. > > > > I'll wave my hands because we've not yet talked much about > > > > conditional members, but it basically looks like this: > > > > > > > > > > > > () { /* common static init code */ > > > > /* specializable init code */ } > > > > > > > > () { /* specializable init code */ } > > > > > > > > Or not. > > > >> Where will the initialization code for both kinds of > > statics be? > > > >> The existing method? > > > > > > > > We have two choices: > > > > - have a new block that gets run once per > > > > specialization, and keep > > > > - merge the two as above, exploiting planned support for > > > > conditional members > > > > > > > > Either way, as you say, we have to ensure that the common init > > > > runs exactly once. > > > >> When using *static, are we only discussing {get,put}? Or > > is this > > > >> also proposing invokestatic changes to allow specialized > > static > > > >> methods? > > > > > > > > Methods too. > > > >> All of the technical details aside, is this something we > > really > > > >> want to expose to the users? They're going to have a > > hard time > > > >> understanding why Foo (or Foo > specialized > > > >> statics while Foo & Foo share the erased > > version. > > > > > > > > I think this is mostly a matter of coming up with the right > > > > syntax, which makes it clear that statics can be per-class or > > > > per-specialization. There are a whole pile of related > > > > specialization-related syntax issues, I'll try to get them > > all in > > > > one place. > > > > > > > > > > > > > > > > > > > > From brian.goetz at oracle.com Tue Mar 29 19:52:58 2016 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 29 Mar 2016 15:52:58 -0400 Subject: Conditional members Message-ID: <56FADD1A.5070508@oracle.com> Yet another in a series of disconnected, bottom-up (starting at the VM) memos laying the groundwork for the enhanced generics model. Basic Problem ============= It may be desirable, for purposes of expressiveness or migration compatibility, to declare class members that are only members of a specific subset of parameterizations of a generic class. Examples include: - Reference-specific API assumptions. In our analysis of the Collection classes, we identified various methods that fail to make the jump to any-generics for various reasons. These include methods like Collection.toArray(), whose signature makes no sense for primitive parameterizations, or Map.get(), which uses `null` (not in the domain of primitives) to indicate "not present." We can't take these methods away from reference instantiations, but we don't want to propagate them into primitive instantiations. - Better implementations enabled by known type parameters. Generic classes will provide generic implementations, but sometimes better implementations are possible when concrete types are known. In this case, an implementation would provide a generic implementation and zero or more implementations that are restricted to more specific implementations. - Functionality available only on specific implementations. For example, List could have a sum() method even though sum() does not make sense on all instantiations. (This is the declaration-site version of what C# enables at the use site with extension methods -- allowing methods to be injected into types, rather than classes.) We've not yet spent a lot of time identifying the proper way to surface this in the language. For methods, one possibility is to use receiver parameters (added in Java SE 8) to qualify the receiver type: int sum(List this) { ... } This gets the point across clearly enough (and is analogous to how C# does extension methods), but has several drawbacks: doesn't scale to fields, nor does it scale well to a conditional-membership model that is anything other than "I am a member of parameterization X". (Where this might fall down, for example, would be when we want members declared as "I am *not* a member of parameterization X".) Note that in the second motivating example, there will be two members signatures with the same name and signature; we want one to take precedence over the other. We call these "conditional" or "restricted" members. Classfile Strawman ================== Here's a strawman of how we might represent this at the VM level. We define a new attribute, `Where`, which can be applied to instance fields, instance methods, and constructors: | Where { u2 name_index; u4 length; u2 restrictionDomain;|// refers to a ParamType constant } The restriction domain indicates the parameterization to which this member is restricted; in the absence of Where attribute, it is assumed to be ThisClass. When loading a parameterization of a generic class, we perform an applicability check for each member as we encounter it; in the model outlined here, this is a straight subtyping check of the current parameterization against the restriction domain. It is possible there could be duplicate applicable methods; this arises when we have a specialization-specific "override", as in: class Foo { // total method m(T) void m(T t) { } // Specialization of m(T) for T=int void m(Foo this, int i) { ... } } When we find a duplicate applicable member, we perform a "more specific" check comparing the restriction domains; in this case, the second method has a restriction domain of Foo, which is more specific than the (implicit) Foo restriction domain of the generic method, so we prefer the second member. This procedure is strictly linear; as each member is read from the classfile, we can make a quick determination as to whether to keep or discard it; if we keep it, we might replace it later with a more specific one as we find it. Modulo cases where there are multiple applicable overloads that are equally specific, it is also deterministic; whether we find the generic version of m() or its specialization first, we'll end up with the same set of members. If there are duplicate applicable members in a classfile where neither's restriction domain is more specific than the other's, then the VM is permitted to make an arbitrary choice (as they are both applicable and equally specific.) The static compiler can work to filter out such situations, if desired, such as imposing a "meet rule"; if we had: void foo(Foo this) void foo(Foo this) a meet rule would require the additional overload void foo(Foo this) From brian.goetz at oracle.com Wed Mar 30 16:26:26 2016 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 30 Mar 2016 12:26:26 -0400 Subject: Classes, specializations, and statics In-Reply-To: <201603301443.u2UEh9Qc005842@d03av04.boulder.ibm.com> References: <1230675344.35291.1458860462924.JavaMail.zimbra@u-pem.fr> <1395529931.1029351.1456257415180.JavaMail.zimbra@u-pem.fr> <201602222111.u1MLBcpn021902@d03av01.boulder.ibm.com> <56CBA674.9030301@oracle.com> <201603182102.u2IL2Hk5027593@d03av02.boulder.ibm.com> <56F4637A.4020600@oracle.com> <201603301443.u2UEh9Qc005842@d03av04.boulder.ibm.com> Message-ID: <56FBFE32.4000208@oracle.com> > Way 3 may be the least intrusive from the JVM's perspective, but it > does complicate migration. One disadvantage is that it requires > changes to declaration sites _and_ usage sites, while way 2 only > requires changes to the declaration site. This may be fine in the > empty collection case, but what about cases where the static field is > public? We can't control those usage sites. Also, it is less transparent -- one more encoding for non-java languages to emulate / reflective code to recognize.