Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > An enum mystery solved

Reply
Thread Tools

An enum mystery solved

 
 
Roedy Green
Guest
Posts: n/a
 
      08-26-2005
I was baffled why the compiler would not let enum constructors access
the enum's static variables.

I consider it a bug, but an understandable bug.

I think the reason is the enum invokes the constructors for the enum
constants in static init code. Somebody was worried that the static
initialisation would not be complete. Yet it is quite safe since the
enum constants are the last bit of static init.

--
Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.
 
Reply With Quote
 
 
 
 
Roedy Green
Guest
Posts: n/a
 
      08-26-2005
On Fri, 26 Aug 2005 05:58:23 GMT, Roedy Green
<(E-Mail Removed)> wrote or quoted :

>I think the reason is the enum invokes the constructors for the enum
>constants in static init code. Somebody was worried that the static
>initialisation would not be complete. Yet it is quite safe since the
>enum constants are the last bit of static init.


I have placed an RFE with Sun to have the restriction repealed. In the
meantime, oddly you can call static METHODS that access the static
variables.

--
Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.
 
Reply With Quote
 
 
 
 
Hemal Pandya
Guest
Posts: n/a
 
      08-26-2005


> I was baffled why the compiler would not let enum constructors access
> the enum's static variables.


If I understand the issue correctly, jls3 8.9 addresses this issue: It
is compile-time error to reference a non-constant (15.2 static
field of an enum type from its constructors, instance initializer
blocks, or instance variable initializer expressions.

>
> I consider it a bug, but an understandable bug.
>
> I think the reason is the enum invokes the constructors for the enum
> constants in static init code. Somebody was worried that the static
> initialisation would not be complete. Yet it is quite safe since the
> enum constants are the last bit of static init.
>

A small test seems to indicate that enum constants are the /first/ bit
of static init and that the static final variables are not initialized
during this enum constant construction.

 
Reply With Quote
 
Thomas Hawtin
Guest
Posts: n/a
 
      08-26-2005
Hemal Pandya wrote:
>
> A small test seems to indicate that enum constants are the /first/ bit
> of static init and that the static final variables are not initialized
> during this enum constant construction.


I think what Roedy missed was the distinction between a compile time
constant and other static finals. A compile time constant will be
inlined and therefore there is no problem. A static final initialised
within static { }/<clinit> will cause a problem.

enum Const {
X;
private static final int x = 1; // compile time constant
private int i;
Const() {
i = x; // fine
}
}

enum Final {
X;
private static final int x = false?null:1; // null is not constant
private int i;
Final() {
i = x; // !! illegal reference to static field from initializer
}
}

You can have a static final reference the enumerated.

enum Ref {
X;
private static final Ref x = X; // fine
}

So constructors must run before user static initialisation. You should
be able to access the static of other classes however.

Tom Hawtin
--
Unemployed English Java programmer
http://jroller.com/page/tackline/
 
Reply With Quote
 
Hemal Pandya
Guest
Posts: n/a
 
      08-26-2005
> In the
> meantime, oddly you can call static METHODS that access the static
> variables.


This seems analogous to the "illegal forward reference" warning when
one static final variable is refers to another static final (but not
constant) variable but can get NullPointerException if the same forward
reference is indirectly achieved using a static method.

 
Reply With Quote
 
Roedy Green
Guest
Posts: n/a
 
      08-26-2005
On 26 Aug 2005 03:27:04 -0700, "Hemal Pandya" <(E-Mail Removed)>
wrote or quoted :

>A small test seems to indicate that enum constants are the /first/ bit
>of static init and that the static final variables are not initialized
>during this enum constant construction.


There is something deeply wrong when Java starts adding arbitrary
restrictions like that making no sense in the high level language.

I decompiled and discovered the construction of the enum constants
came last. What is your code that the inits come after the
construction? Why could not the compiler put it before and be done
with this silly restriction, simultaneously making it safer to use
static methods.

here is an example:

public enum Trees
{
PINE( true ),
ASPEN ( false );

private static int coniferousCount;

Trees( boolean coniferous )
{
counter( coniferous );
}

static void counter( boolean coniferous )
{
if ( coniferous ) coniferousCount++;
}

}


decompiles as:

public final class Trees extends Enum
{

public static final Trees[] values()
{
return (Trees[])$VALUES.clone();
}

public static Trees valueOf(String s)
{
return (Trees)Enum.valueOf(Trees, s);
}

private Trees(String s, int i, boolean flag)
{
super(s, i);
counter(flag);
}

static void counter(boolean flag)
{
if(flag)
coniferousCount++;
}

public static final Trees PINE;
public static final Trees ASPEN;
private static int coniferousCount;
private static final Trees $VALUES[];

static
{
PINE = new Trees("PINE", 0, true);
ASPEN = new Trees("ASPEN", 1, false);
$VALUES = (new Trees[] {
PINE, ASPEN
});
}
}
--
Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.
 
Reply With Quote
 
Roedy Green
Guest
Posts: n/a
 
      08-26-2005

>enum Final {
> X;
> private static final int x = false?null:1; // null is not constant
> private int i;
> Final() {
> i = x; // !! illegal reference to static field from initializer
> }
>}
>

Here is your code modified slightly to make it compile:

enum Final {
X; // enum constant
private static final int x = Math.min(2,1);
// final but not constant
private int i;
Final()
{
// i = x; // !! illegal reference to static field from
initializer
}
}

Here is how it decompiles:

final class Final extends Enum
{

public static final Final[] values()
{
return (Final[])$VALUES.clone();
}

public static Final valueOf(String s)
{
return (Final)Enum.valueOf(Final, s);
}

private Final(String s, int j)
{
super(s, j);
}

public static final Final X;
private static final int x = Math.min(2, 1);
private int i;
private static final Final $VALUES[];

static
{
X = new Final("X", 0);
$VALUES = (new Final[] {
X
});
}
}

You can see that had the i=x been allowed, it should have been fine.
The constructors are run after the x = Math.min(2,1) are they not?
--
Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.
 
Reply With Quote
 
Thomas Hawtin
Guest
Posts: n/a
 
      08-26-2005
Roedy Green wrote:
> On 26 Aug 2005 03:27:04 -0700, "Hemal Pandya" <(E-Mail Removed)>
> wrote or quoted :
>
>
>>A small test seems to indicate that enum constants are the /first/ bit
>>of static init and that the static final variables are not initialized
>>during this enum constant construction.

>
>
> There is something deeply wrong when Java starts adding arbitrary
> restrictions like that making no sense in the high level language.


Initialisation has got to be done in some order. Doing it in the order
presented in the source code seems like the method of least surprises to me.

> I decompiled and discovered the construction of the enum constants
> came last. What is your code that the inits come after the
> construction? Why could not the compiler put it before and be done
> with this silly restriction, simultaneously making it safer to use
> static methods.
>
> here is an example:
>
> public enum Trees
> {
> PINE( true ),
> ASPEN ( false );
>
> private static int coniferousCount;
>
> Trees( boolean coniferous )
> {
> counter( coniferous );
> }
>
> static void counter( boolean coniferous )
> {
> if ( coniferous ) coniferousCount++;
> }
>
> }


This is an irrelevant example. It does not do any user static
initialisation.

Here's my example:

enum Order {
X;
private static final long time = System.currentTimeMillis();
}

$ javap -c Order
....
static {};
Code:
0: new #4; //class Order
3: dup
4: ldc #7; //String X
6: iconst_0
7: invokespecial #8; //Method "<init>"Ljava/lang/String;I)V
10: putstatic #9; //Field X:LOrder;
13: iconst_1
14: anewarray #4; //class Order
17: dup
18: iconst_0
19: getstatic #9; //Field X:LOrder;
22: aastore
23: putstatic #1; //Field $VALUES:[LOrder;
26: invokestatic #10; //Method
java/lang/System.currentTimeMillis)J
29: putstatic #11; //Field time:J
32: return


Bytes [0, 13) creates the constant. Bytes [13, 26) do the rest of the
enum initialisation. Bytes [26, 32) are my initialisation.

Clearly the enum constants are created first. Which is useful if I
wanted any static finals involving the enumeration that they are in.

Tom Hawtin
--
Unemployed English Java programmer
http://jroller.com/page/tackline/
 
Reply With Quote
 
Roedy Green
Guest
Posts: n/a
 
      08-26-2005
On Fri, 26 Aug 2005 19:06:09 GMT, Roedy Green
<(E-Mail Removed)> wrote or quoted :

> private static final int x = Math.min(2,1);


what term do you use to distinguish been a constant like this:

private static final int X = Math.min(2,1);

and like this:

private static final int Y = 42;


The second is known at compile time, can be used in case labels, is
in-lineable.
--
Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.
 
Reply With Quote
 
Thomas Hawtin
Guest
Posts: n/a
 
      08-26-2005
Roedy Green wrote:
>
> Here is your code modified slightly to make it compile:
> [...]
> Here is how it decompiles:
> [...]
> You can see that had the i=x been allowed, it should have been fine.
> The constructors are run after the x = Math.min(2,1) are they not?


I don't think you should depend upon your decompiler being accurate.
javap -c is the way to go. You can see that the actual byte code is
different from what your decompiler is claiming.

Tom Hawtin
--
Unemployed English Java programmer
http://jroller.com/page/tackline/
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
RE: Populating a dictionary, fast [SOLVED SOLVED] Michael Bacarella Python 26 11-20-2007 03:02 PM
Vanishing buttons mystery "solved" No One ASP .Net 0 10-28-2004 04:17 PM
Update: IE6 Browsing Mystery Solved! Julie P. Computer Support 71 07-29-2004 10:20 PM



Advertisments