One final stab at improving lambda serialization

David M. Lloyd david.lloyd at redhat.com
Thu Aug 29 12:26:18 PDT 2013


On 08/27/2013 04:01 PM, David M. Lloyd wrote:
> On 08/19/2013 10:37 AM, Brian Goetz wrote:
>  > [...]
>> The other failure has to do with order-of-capture.
>>
>> *Old code**
>> *     *New code**
>> *     *Result**
>> *
>> String s1 = "foo";
>> String s2 = "bar";
>> Runnable r = new Runnable() {
>>      void run() {
>> foo(s1, s2);
>>      }
>> };
>>
>>     String s1 = "foo";
>> String s2 = "bar";
>> Runnable r = new Runnable() {
>>      void run() {
>>          String s = s2;
>> foo(s1, s);
>>      }
>> };
>>     On deserialization, s1 and s2 are effectively swapped.
>>
>> This fails because the order of arguments in the implicitly generated
>> constructor of the inner class changes due to the order in which the
>> compiler encounters captured variables.  If the reordered variables were
>> of different types, this would cause a type-1 failure, but if they are
>> the same type, it causes a type-2 failure.
>
> This appears to not strictly be accurate.  In my tests I've found that
> yes the constructor parameter ordering may indeed differ (based on this
> or (potentially) even any other compiler-specific factor), however since
> the constructor is not actually used during deserialize (the mandatory
> no-arg constructor of the first non-serializable superclass is used
> instead), this difference is irrelevant (to this particular problem).
> The serialization values are stored by field name in the serialization
> stream and filled in via reflection; every Java compiler I have access
> to names these fields e.g. "val$s1" and "val$s2" with the local variable
> name stored in the field name.  From my testing, this case seems like it
> would work "as expected" (and, given the apparent complete ubiquity of
> compiler implementation, probably ought to just be formalized in at
> least the serialization spec by now, if not the JLS itself, but that's
> really a tangential topic).
>
> Also worth noting is that the outer class instance lives in a field
> called "this$0".
>
> Anyway because this has always "just worked", I think that the
> definition of "significant [change]" used later on in your proposal
> should probably be changed to removing the "order" (and even "number")
> of captured arguments; the former is handled as above, and the latter
> works predictably by simply extrapolating the serialization spec rules
> about adding/removing fields to captured variables.  This is the basis
> of my earlier gripes about only using capture order (i.e. an array,
> essentially) for captures instead of names (i.e. a map like
> serialization does).

After internal review, and apart from this background factual 
clarification, Red Hat is satisfied that the proposed improvements will 
avoid the vast majority of problems that we are concerned about.

-- 
- DML


More information about the lambda-spec-observers mailing list