evum constructor gotcha

R

Roedy Green

Perhaps I'm missing something, but this seems simple: To
initialize the static field, you need to construct an enum
instance for it to refer to. How can the constructor get the
value of a reference to an instance that has not yet finished
being constructed?

In a regular class, statics are initialised before any instance
variables. The enum constants are a sort of implied static
initialisation.

What if the language had been defined so the enum constants were
created (i.e. their constructors run) after the other static
initialisation?

The disadvantage is statics could not refer to enum constants.

So what if you had allowed two sets of static inits, one before the
enum definitions, and one after. In other words, allow the programmer
to determine the order of initialisation. Let him figure out how best
to avoid forward references.


--
Roedy Green Canadian Mind Products
http://mindprod.com

"Patriotism is fierce as a fever, pitiless as the grave, blind as a stone, and as irrational as a headless hen."
~ Ambrose Bierce (born: 1842-06-24 died: 1914 at age: 71)
 
M

markspace

Roedy said:
But it doesn't make sense that instance constants are evaluated prior
to static constants.


It does to me. Static blocks and static variables are always
initialized in the order they are encountered in the class source file:

public enum Example {

FIRST( THE_ANSWER ),
SECOND( THE_ANSWER );

private static final int THE_ANSWER = 42;

private Example( int value ) {
// do something with value...
}
}


So it makes perfect sense that the static value "FIRST" (the enum) gets
initialized before THE_ANSWER;
I know it is in the JLS. That is still Mickey Mouse language design.


I might agree with you there. It may have been more useful to have the
enum values themselves initialized last, rather than first.
 
R

Roedy Green

There seems to be a problem accessing the static final values in the
enum constructor. Is this a bug, or one of those quirky features of
the way enums are implemented?

Putting aside for a second implementation complexities, what is the
problem at the language level?

It is a circularity problem. An enum constructor might refer to a
static final before its value had been computed, and static final
might refer to an enum constant before it has been constructed.

Spreadsheets try to solve this by dependency analysis, to work out a
"natural" order.

Java considers this approach too vague, and insists programmers
physically order the code to handle the initialisation in the desired
order.

I use an fairly elaborate sorting scheme for my fields, enforced by an
Intellij IDEA plugin called the Rearranger largely to ensure that
fields are kept in reasonable sensible order initialisation
dependencies. Sometimes I end up renaming variables to modify the
dependency order, a practice I find repugnant.

I recall once to my horror letting VAJ tidy my BigDate code (by
reordering) and though it would compile, it completely stopped working
because the initialisation dependencies were disturbed.

My approach now, when order get dicey is to create a static init block
and do all the inits in there. static final declarations ensure I
don't forget anything.

It seems to me, the proper solution is just to use the existing
general Java rule to avoid circular definitions -- no forward
references. You then treat the enum definitions just like any other
static init that created some objects other static init code might
like to reference. This means a change to the language to allow
static definitions prior to the enum constant definitions as well as
after.



--
Roedy Green Canadian Mind Products
http://mindprod.com

"Patriotism is fierce as a fever, pitiless as the grave, blind as a stone, and as irrational as a headless hen."
~ Ambrose Bierce (born: 1842-06-24 died: 1914 at age: 71)
 
A

Andreas Leitgeb

Joshua Cranmer said:
... or you would have to separate memory reservation and
initialization. Such a static initializer would look like this:

new ThingsAndAntis
setstatic ThingsAndAntis.FOO
new ThingsAndAntis
setstatic ThingsAndAntis.BAR

getstatic ThingsAndAntis.FOO
getstatic ThingsAndAntis.BAR
invokespecial <init>(LThingsAndAntis;)V
getstatic ThingsAndAntis.BAR
getstatic ThingsAndAntis.FOO
invokespecial <init>(LThingsAndAntis;)V

That's exactly what I had in mind.
I wonder if the bytecode-verifier in the JVM would accept
a thusly handcrafted class.
In principle, that much is doable, but you run into the same problems I
mentioned before: you limit what you can use in the constructor.

Sure, still limited. just the limits pushed a tiny bit further.

PS: I once was in the situation of "needing" that (and iirc I even started
a fruitless thread about it here back then). In the end I replaced the
Enum by an int whose bits I then twiddled the way I needed to get it's
"anti". But then again, even *with* such a feature I'd have turned to
use int sooner or later. So no case for it.

PPS: These days, I find primitive-like structs (compounds of primitives
that reside on stack rather than on heap) a much more interesting
Java-fantasy.
 
M

markspace

Joshua said:
Which would be more useful
to the average programmer, do you think: to be able to use the enum
variables within static initializers, or to use static initializers in
enum variables?

This is a good point, one I hadn't considered. Normally, I think I
would tend to initialize enums from constants more often, but then I
think I actually use enums with no method body at all most often, so
really it doesn't matter.

Through use of nested classes, it is possible to achieve
the other effect from what is chosen, so the question is more one of the
likelier usage.

Now this is a cool idea I hadn't considered.

public enum Example2 {

FIRST( ONE ),
SECOND( TWO ),
THIRD( THREE );

private static class Consts {
final static int ONE = 1;
final static int TWO = 2;
final static int THREE = 3;
}

private Example2( int value ) {
// do something with value...
}
}
 
L

Lew

Roedy said:
In a regular class, statics are initialised before any instance
variables. The enum constants are a sort of implied static
initialisation.

That is true. The JLS explicates this in §8.9.

E.g.,

public enum Foo
{
ROY, GRAHAM, BIV;
}

is roughly equivalent to

public final class Foo extends Enum <Foo>
{
public static final Foo ROY = new Foo( "ROY" );
public static final Foo GRAHAM = new Foo( "GRAHAM" );
public static final Foo BIV = new Foo( "BIV" );

// all other static initialization occurs here

private final String name;
// any instance final variable initialized here will not
// have any knowledge of the later static inits
// but the constructor can see the instance variables
private Foo( String name )
{
this.name = name;
}
// toString(), name(), etc.
}
What if the language had been defined so the enum constants were
created (i.e. their constructors run) after the other static
initialisation?

The disadvantage is statics could not refer to enum constants.

So what if you had allowed two sets of static inits, one before the
enum definitions, and one after. In other words, allow the programmer
to determine the order of initialisation. Let him figure out how best
to avoid forward references.

That's what you sort of get manually with Patricia's suggestion of a static
initializer block that goes back and fixes up what a pre-init would have done.
IOW, Java does indeed provide a mechanism to work around the restrictions on
init order.

As Eric explained, fixing the order avoids certain problems with the approach
that you suggest. Sure, it's a compromise, but given the ability to do what
you need to without the more complicated implementation, it amounts to a
difference that makes no difference.

All right, you have to add a dozen or so lines of code. C'est la vie.

Did you read the "Discussion" block in the JLS that goes into why they chose
not to go down the route you suggest? It may not seem like a complete
explanations, though I do find it quite indicative. It does point up the
sorts of problems we'd have otherwise - then you'd be posting about the tricky
convolutions of circular references in enum and calling that "Mickey Mouse".

 
L

Lew

markspace said:
It does to me. Static blocks and static variables are always
initialized in the order they are encountered in the class source file:

public enum Example {

FIRST( THE_ANSWER ),
SECOND( THE_ANSWER );

private static final int THE_ANSWER = 42;

private Example( int value ) {
// do something with value...
}
}


So it makes perfect sense that the static value "FIRST" (the enum) gets
initialized before THE_ANSWER;

Actually, you picked a bad example. THE_ANSWER is a compile-time constant and
will not be initialized at all, rather, it will be used as the compiled-in
value 42.

A better example would be like:

// assume a suitable Foo

public enum Example
{
FIRST( THE_ANSWER ),
SECOND( THE_ANSWER );

private static final Foo THE_ANSWER = new Foo();

private Foo foo;
Example( Foo fu )
{
this.foo = fu;
}
@Override public String toString()
{
return foo.getName(); // NPE
}
}
 
L

Lew

Andreas said:
PPS: These days, I find primitive-like structs (compounds of primitives
that reside on stack rather than on heap) a much more interesting
Java-fantasy.

Now that horse I back!

That is a feature that Java should have. I would say, rather, compounds of
compile-time constants, or even more relaxed, compounds of final variables.
 
M

markspace

Lew said:
That is a feature that Java should have. I would say, rather, compounds
of compile-time constants, or even more relaxed, compounds of final
variables.

I think to be viable the compounds would have to specifically allow
non-final variables. Something like this:

Type stuff = class Type {
int len;
int id;
};

fill( stuff );
// ...

private static fill( Type filler ) {
filler.len = 2;
filler.id = 42;
}


Ought to be a prime candidate for being kept on the stack rather than
allocated in the heap.

Where I find this applicable is something like this

int i = 42;
String s = String.toString( i );
// do something with s...


public class String {
public String toString( int i ) {
char[] c = new char[11];
int len; // of string
// fill c and set len
return new String( c, 0, len );
}
}

Which is similar to what the Java library does now. All of the objects
above should be strong candidates for some sort of "return optimization"
and kept on the stack. Strings don't happen to be mutable but that's
immaterial to the stack vs. heap discussion.

If you look back to post we had here about a year ago, on why Java was
so much slower than C when writing to a stream, that's the modification
I eventually made to make Java actually beat C (on our systems anyway,
not the OP's). Don't allocate objects on the heap each time through the
print loop, allow for one single mutable object that gets reused. A
stack-based object would simulate that mutable object really well,
probably better in terms of optimization and speed.

I think some return optimization of this sort could really speed a lot
of leaf methods up in Java.


That bad bit of this, I think, is that modern CPUs have relatively small
caches on their stacks. Small cache means having to fetch from main
memory on a cache miss (or if it fills) so that'll slow you down if you
try to push huge structures onto the stack. Maybe this isn't such a
great idea and we need to think about how to make heap memory allocation
faster to reduce the penalty for a "new" close to 0.
 
L

Lew

markspace said:
I think to be viable the compounds would have to specifically allow
non-final variables. Something like this:

Type stuff = class Type {
int len;
int id;
};

Final variables would be enough if they pointed to mutable objects, but
clumsier to use than non-final ones.

class Holder
{
int len;
int id;
}
class Arg
{
final Holder holder = new Holder();
final MutableFoo mf = new MutableFoo();
}

public class ShowStackArg
{
final Random rand;
public boolean doSomething( stack Arg arg )
{
int length = arg.holder.len;
arg.holder.id = rand.nextInt();
...
}
static void main( String [] args )
{
ShowStackArg show = new ShowStackArg();
Arg arg = new Arg();
arg.holder.len = 17;

show.doSomething( arg );

int id = arg.holder.id;
...
}
}
 
L

Lew

Lew said:
public class ShowStackArg
{
final Random rand;
public boolean doSomething( stack Arg arg )
{
int length = arg.holder.len;
arg.holder.id = rand.nextInt();
...
}
static void main( String [] args )
{
ShowStackArg show = new ShowStackArg();
Arg arg = new Arg();
arg.holder.len = 17;

show.doSomething( arg );

int id = arg.holder.id;
...
}
}

My example convinced me that markspace is right,
 
M

markspace

Lew said:
Actually, you picked a bad example. THE_ANSWER is a compile-time
constant and will not be initialized at all, rather, it will be used as
the compiled-in value 42.


On my system, that construct gives "Illegal forward reference," unless I
messed something else up.
 
A

Andreas Leitgeb

Lew said:
Now that horse I back!
That is a feature that Java should have. I would say, rather, compounds of
compile-time constants,

Huh? That's a different horse then. One, whose use I do not yet see.

I rather thought of compounds of variables, stored on the stack
or embedded into an array of such compounds.
 
A

Andreas Leitgeb

Andreas Leitgeb said:
Huh? That's a different horse then. One, whose use I do not yet see.

Ok, forget it. Just saw that you unmounted that horse, too, already. :)
 
A

Arne Vajhøj

Joshua said:
Even if implemented differently, the two conditions must probably remain
the same. Consider that the usage of enums would most likely require
them to act as static variables. Now consider how to initialize them.

Any "Joshua Bloch compliant" implementation would so.

But as synonym for int literal ...

Arne
 
A

Arne Vajhøj

Andreas said:
PPS: These days, I find primitive-like structs (compounds of primitives
that reside on stack rather than on heap) a much more interesting
Java-fantasy.

That could be rather handy in some cases.

There is a sort of a gap between the simple types and objects.

Arne
 

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,223
Latest member
Jurgen2087

Latest Threads

Top