ordinal() returns inconsistent values?

T

Todd

Hello,

I have recently been told that the ordinal() method in a Java enum
will not necessarily return the same value in different invocations of
the JVM. Has anyone else found this?

BTW, the semantics of the enum will stay the same, an enumerated value
that was once greater than another will continue to be so. It is just
that the absolute value of the declared enumeration will not
necessarily be the same from run to run. This indicates to me that
one would not be able to retrieve an enumerated element by a stored
ordinal value. Further, the ordinal could be a value greater than the
number of enumerated elements, making values()[ordinal()] suspect as
well.

Any insights are appreciated,
Todd
 
M

Mayeul

Hello,
I have recently been told that the ordinal() method in a Java enum
will not necessarily return the same value in different invocations of
the JVM. Has anyone else found this?

Never observed this, and it would be contradictory with the JavaDoc of
Enum.ordinal() . I often expect ordinal() to behave as specified, and
have never noticed this expectation to break anything.
[...] This indicates to me that
one would not be able to retrieve an enumerated element by a stored
ordinal value.

Well that /is/ pretty unsafe to do anyway. What if you need to
add/remove/swap enum values?
I usually store their name instead, or try to think up some safe enough
serialization.
 
J

Joshua Cranmer

I have recently been told that the ordinal() method in a Java enum
will not necessarily return the same value in different invocations of
the JVM. Has anyone else found this?

To do so would contradict the API:
public final int ordinal()

Returns the ordinal of this enumeration constant (its position in
its enum declaration, where the initial constant is assigned an ordinal
of zero). Most programmers will have no use for this method. It is
designed for use by sophisticated enum-based data structures, such as
EnumSet and EnumMap.

Returns:
the ordinal of this enumeration constant
 
T

Todd

To do so would contradict the API:
public final int ordinal()

     Returns the ordinal of this enumeration constant (its position in
its enum declaration, where the initial constant is assigned an ordinal
of zero). Most programmers will have no use for this method. It is
designed for use by sophisticated enum-based data structures, such as
EnumSet and EnumMap.

     Returns:
         the ordinal of this enumeration constant

I fully agree. I was told that the JavaDocs were wrong. I tried
locating a source on the web to corroborate the assertion, but
couldn't find one.
 
J

John B. Matthews

Todd said:
To do so would contradict the API:
public final int ordinal()

     Returns the ordinal of this enumeration constant (its position in
its enum declaration, where the initial constant is assigned an ordinal
of zero). Most programmers will have no use for this method. It is
designed for use by sophisticated enum-based data structures, such as
EnumSet and EnumMap.

     Returns:
         the ordinal of this enumeration constant
[...]
I fully agree. I was told that the JavaDocs were wrong. I tried
locating a source on the web to corroborate the assertion, but
couldn't find one.

I'd have thought to avoid ordinal(), as suggested by Joshua Bloch,
"Item 31: Use instance fields instead of ordinals."

Regarding serialization, section 1.12 of "Java Object Serialization
Specification," entitled "Serialization of Enum Constants," mentions
using "the value returned by the enum constant's name method."

<http://java.sun.com/javase/6/docs/platform/serialization/spec/serialTOC.html>
 
L

Lew

I fully agree.  I was told that the JavaDocs were wrong.  I tried
locating a source on the web to corroborate the assertion, but
couldn't find one.

"I was told ..."

Who told you? How authoritative is this source usually? What
evidence did they give for this outrageous assertion? Wouldn't it
break 'EnumSet' and 'EnumMap' if your source were correct?
 
M

Mike Schilling

John said:
Regarding serialization, section 1.12 of "Java Object Serialization
Specification," entitled "Serialization of Enum Constants," mentions
using "the value returned by the enum constant's name method."

<http://java.sun.com/javase/6/docs/platform/serialization/spec/serialTOC.html>

Of course. You wouldn't want stuff to break [1] because the enum values had
been reordered between serialization and deserialization.

1. E.g. to silently turn SPRING into AUTUMN because the order was changed
from chronological to alphabetical.
 
M

Mike Schilling

Lew said:
"I was told ..."

Who told you? How authoritative is this source usually? What
evidence did they give for this outrageous assertion? Wouldn't it
break 'EnumSet' and 'EnumMap' if your source were correct?

To the last point, not necessarily, so long as it's consistent within a JVM
session and those classes are persisted in a way that doesn't assume it's
consistent across JVMs. Likewise, I think (though I could be wrong) that

1. Create a TreeMap
2. Serialize it to a file
3. Make code changes that change the ordering defined on its keys
4. Deserialize it

works.
 
D

Daniel Pitts

Hello,

I have recently been told that the ordinal() method in a Java enum
will not necessarily return the same value in different invocations of
the JVM. Has anyone else found this?

BTW, the semantics of the enum will stay the same, an enumerated value
that was once greater than another will continue to be so. It is just
that the absolute value of the declared enumeration will not
necessarily be the same from run to run. This indicates to me that
one would not be able to retrieve an enumerated element by a stored
ordinal value. Further, the ordinal could be a value greater than the
number of enumerated elements, making values()[ordinal()] suspect as
well.

Any insights are appreciated,
Todd
That is incorrect. If the order remains the same (and it must), and the
ordinal() result corresponds with the index into the values() array (and
it must), and the values() array can not contain null (and it mustn't),
then the ordinal() value must be the same, for the same enum class,
every invocation.
 
T

Todd

Who told you?  How authoritative is this source usually?  What
evidence did they give for this outrageous assertion?  Wouldn't it
break 'EnumSet' and 'EnumMap' if your source were correct?

A fellow here at work who has one of the Sun certifications. He made
the statement yesterday, but is not in today for me to get more
clarification.
 
J

Joshua Cranmer

I fully agree. I was told that the JavaDocs were wrong. I tried
locating a source on the web to corroborate the assertion, but
couldn't find one.

If you've ever looked at how enums are created (via javap -c), you'll
notice that you'll get something akin to [1]:

public final class Seasons extends Enum<Seasons> {
public final static Seasons SPRING = new Seasons("SPRING", 0);
public final static Seasons SUMMER = new Seasons("SUMMER", 1);
public final static Seasons AUTUMN = new Seasons("AUTUMN", 2);
public final static Seasons WINTER = new Seasons("WINTER", 3);

private Seasons(String name, int ordinal) {
super(name, ordinal);
}
}

In other words, the ordinal is hardcoded into the class file at compile
time. Reading the JavaDocs should also give you this opinion, since the
only constructor it has is protected Enum(String name, int ordinal).

[1] I'm eliding the $VALUES variable and initialization, as well as the
values and valueOf functions. Also, what a coincidence that the four
seasons have the same lengths in their words in English.
 
A

Arne Vajhøj

I fully agree. I was told that the JavaDocs were wrong. I tried
locating a source on the web to corroborate the assertion, but
couldn't find one.

Unless there are evidence supporting the claim, then I would
expect the docs to be correct and the "smart guy" to be
wrong.

Arne
 
A

Arne Vajhøj

A fellow here at work who has one of the Sun certifications. He made
the statement yesterday, but is not in today for me to get more
clarification.

Being Java certified is no guarantee to be correct on all
Java matters.

Arne
 
R

Roedy Green

I have recently been told that the ordinal() method in a Java enum
will not necessarily return the same value in different invocations of
the JVM. Has anyone else found this?

If you add new enum constants, or run a code tidier, you will get
different ordinal values.

Assuming you did not change the code, perhaps you failed to clean
recompile the universe after the last change and a mix of old and new
code was used that caused the anomaly.

Can you make this happen on command in an SSCCE?

It is dangerous to write Java code that depends on the ordinal
remaining invariant. Invent some invariant field on each enum
constant which might just be a single letter or a short word for use
in databases to represent the value.
 
L

Lew

Roedy said:
It is dangerous to write Java code that depends on the ordinal
remaining invariant. Invent some invariant field on each enum
constant which might just be a single letter or a short word for use
in databases to represent the value.

Amen to that!

More generally one nearly always faces the task of mapping an enum to some
untyped representation and back. Of course, enums build that facility in
already with 'name()' and 'valueOf()'.

<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9>
"... the automatically generated methods (values() and valueOf(String)) or
methods that override the final methods in Enum: (equals(Object), hashCode(),
clone(), compareTo(Object), name(), ordinal(), and getDeclaringClass())."

<http://java.sun.com/javase/6/docs/api/java/lang/Enum.html#name()>
"Most programmers should use the toString() method in preference to this one,
as the toString method may return a more user-friendly name." (Original is in
boldface.)

Huh? The very API Javadocs tell you strongly not to use 'name()', which
corresponds to the static 'valueOf(String)'. But what's the static method
that balances 'toString()'? I call mine 'fromString()'.

There's a Hibernate enum converter that takes as parameters the names of the
to- and fro- methods, defaulting to 'name()' and 'valueOf()'.

One's 'fromString()' can be as forgiving or strict as one cares to make it. I
like mine to be case sensitive and to fall back to 'valueOf()' if nothing
better fits. 'fromString( "foo" )' and 'fromString( "FOO" )' would both
return the 'FOO' enum constant in my example below.

template:

/** ${name}.
*/
public enum ${name}
{
// CONSTANTS GO HERE, e.g.,
// FOO( "foo" ),
;

private final String repr;

/**
* Constructor.
* @param rep String representation of enum value.
*/
${name}( String rep )
{
this.repr = rep;
}

@Override
public final String toString()
{
return this.repr;
}

/**
* Look up enum constant from String representation.
* @param rep String representation of enum value.
* @return ${name} constant matching the representation.
*/
public static ${name} fromString( final String rep )
{
if ( rep == null )
{
return null;
}
for ( ${name} val : values() )
{
if ( rep.equals( val.toString() ) )
{
return val;
}
}
return valueOf( rep );
}
}
 
R

Roedy Green

If you've ever looked at how enums are created (via javap -c), you'll
notice that you'll get something akin to [1]:

I have posted decompilations of several enum-using programs at
http://mindprod.com/jgloss/enum.html

I see no sign of how ordinals could change without changing source and
recompiling. I have not studied the serialization code. I use it all
the time, and have never noticed anything untoward.

As usual, your program is likely confidential, long and complex, and
when you try to write an SSCCE the problem goes way. The IntelliJ
people have assured me, in that case, they are happy to get a huge
SSCCE, so long it is complete enough for them to run it.

Is your code posted anywhere?

For now, I would suggest a clean compile, and see if the assignments
magically become stable.

By any chance are you storing ordinals in a database or flat files?
These will go out of date the instant you add another enum or tidy the
source code enum order.
 
T

Todd

Everyone,

Thanks for all of the responses. I have had a chance to speak with
the originator of the issue and he said a guru at a prior workplace
told he and his colleagues to be wary of ordinal. My colleague
believes this statement was made due to the docs indicating that
ordinal is likely to be of little use to developers and is primarily
for internal use. He has yet to get a response from the guru for
confirmation or other sources.

BTW, my colleague cited Roedy's page on enums, not to defend his
position, but just as a reference.

Thanks for all the good info and if/when I get a source for the
warning against ordinal, I will post it.

Todd
 
L

Lew

Todd said:
Everyone,

Thanks for all of the responses. I have had a chance to speak with
the originator of the issue and he said a guru at a prior workplace
told he and his colleagues to be wary of ordinal. My colleague
believes this statement was made due to the docs indicating that
ordinal is likely to be of little use to developers and is primarily
for internal use. He has yet to get a response from the guru for
confirmation or other sources.

BTW, my colleague cited Roedy's page on enums, not to defend his
position, but just as a reference.

Thanks for all the good info and if/when I get a source for the
warning against ordinal, I will post it.

Some of the real dangers of ordinals have been explained in this thread,
including by Roedy in the message to which you responded here.
 
A

Arne Vajhøj

Thanks for all of the responses. I have had a chance to speak with
the originator of the issue and he said a guru at a prior workplace
told he and his colleagues to be wary of ordinal. My colleague
believes this statement was made due to the docs indicating that
ordinal is likely to be of little use to developers and is primarily
for internal use. He has yet to get a response from the guru for
confirmation or other sources.

So you heard from someone that heard from someone that got
the info from an unidentified source.

:)

BTW, ordinal returning inconsistent values and ordinals
being of little value for programmers are two very different things.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top