JLS tweaks

Archie Cobbs archie at dellroad.org
Thu Mar 13 16:22:50 UTC 2014


On Thu, Mar 13, 2014 at 5:08 AM, Peter Levart <peter.levart at gmail.com>wrote:

>  On 03/11/2014 07:09 PM, Archie Cobbs wrote:
>
> On Tue, Mar 4, 2014 at 2:38 AM, Remi Forax <forax at univ-mlv.fr> wrote:
>
>>
>>  It seems like the JVM spec gets it right - i.e., you can do (mostly)
>>> whatever you want prior to super()/this() as long as it doesn't try to make
>>> use of an uninitialized 'this', and no uninitialized 'this' can escape. It
>>> seems reasonable to want the JLS to more closely mirror this sensible
>>> stance.
>>>
>>> I must be missing something...
>>>
>>
>> The rules of Java the language are less permissive than the rules of the
>> JVM regarding uninitialized instance, that's true.
>> But at least, the Java rules is simple to understand to anyone. Adding
>> complexity here will not worth it and as Brian mention,
>> you can still call a static method inside this() or super().
>>
>
>  I don't see how any complexity would be added (that is, for the
> programmer). What's being added is flexibility. If someone wants to
> continue to make super()/this() the first line of every constructor, they
> can happily continue do so.
>
>
> Hi Archie,
>
> Would you want this to be allowed too:
>
>     public class C extends B {
>         public C(boolean b) {
>             if (b) {
>                 super("YES");
>                 // we may now use this...
>                 this.method();
>             } else {
>                 // we may not use this before call to super
>                 super("NO");
>                 // we may now use this...
>             }
>         }
>     }
>

Yes.

Or, for example:

  public C(int x, int y) {
     if (y > 0)
        x = Math.min(x, y);
     super(x);
  }


> What about the following:
>
>     public class C extends B {
>         public C() {
>             try {
>                 super();
>                 if (Math.random() > 0.5L) throw new RuntimeException();
>             } catch (RuntimeException e) {
>                 // can we use 'this' here?
>             }
>             // is 'this' fully initialized here?
>         }
>     }
>

No... because exactly once initialization cannot be proven.

As you point out, the same compiler logic that verifies final field
initialization ("initialize exactly once and don't use until intialized")
could be re-used for 'this' initialization ("initialize exactly once and
don't use until initialized").

In your try/catch example, if you replaced 'this' initialization with final
field intialization, you would get a compiler error. So the same thing
would happen in your example - the compiler would complain that in the
catch block it could not verify 'this' was initialized (if you tried to use
it).

Moreover, even if the compiler did allow your example the JVM would reject
it. The JVM spec requires the bytecode verifier to do data flow analysis to
verify exactly once 'this' initialization.


> Just to illustrate this is not a simple problem. But there might be a
> solution that is similar to a feature already present in Java language.
> Namely: the final variables and definitive assignment rules. We could treat
> 'this' (explicit and implicit) as a final instance field that is definitely
> not assigned at the start of a constructor. Any call to super(...) or
> this(...) is only possible in parts of constructor flow where 'this' is
> definitely not assigned and has the effect of making 'this' definitely
> assigned after the call. 'this' should either be definitely assigned or
> definitely unassigned at all non-exceptional exit paths from the
> constructor or else there is a compile-time error. If it is definitely
> assigned, nothing is done, if it is definitely unassigned, a synthetic call
> to super() is generated as the first instruction in the constructor.
>
> So if we threat 'this' as a final instance field for which the assignment
> state is tracked by the compiler, every explicit or implicit use of 'this'
> should only be allowed in parts of constructor flow where it is definitely
> assigned.
>

Exactly. The same compiler logic that already exists for final field
intiailization can be re-used mostly as-is.


> I don't see this as any more complex or unsafe as the rules for final
> fields. But I don't know if it is compatible with JVM rules.
>

The JVM has exactly this same rule, so it's compatible.

This change simply aligns what the compiler permits with what the JVM
permits.

So in summary:

   - There is no weakening of type safety with this change
   - Change is fully compatible with existing source code and current JVM
   spec
   - The same logic for checking final field initialization that already
   exists in the compiler can be re-used for 'this' initialization
   - This feature has been requested many times in the past (as Brian
   pointed out)

This one really seems like a no-brainer to me (just my own opinion of
course).

-Archie

-- 
Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20140313/86c2a70e/attachment-0001.html>


More information about the compiler-dev mailing list