Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Using Enumerated Types as Array Indexes

Reply
Thread Tools

Using Enumerated Types as Array Indexes

 
 
KevinSimonson
Guest
Posts: n/a
 
      08-16-2011
Ada, the programming language mandated for the military for a time,
was a wonderful language that didn't deserve to die. But it did, and
now Java is alive and well and nobody seems to be doing anything at
all with Ada.

Java is a pretty handy language in its own right. But in Ada one
could define arrays to be indexed by enumerated types. Can Java do
that? If not, why not?

I wrote a piece of code that implements an array of <String>s, indexed
by objects of class <Coord>, an enumerated type, that I'm including
below. Obviously the functionality of this class could be copied to
make it possible to create _virtual_ arrays of _any_ element class,
indexed by _any_ enumerated type. Isn't this precisely the thing
generics were designed for? But how does one write a generic class to
implement an array indexed by enumerated types?

I've also included below three attempts to create a generic type that
implements an array indexed by enumerated types, but none of them
compile. Can anyone give me some pointers on this?

Kevin Simonson



Script started on Tue Aug 16 06:47:31 2011
sh-4.1$ ls
ArrayEnum.class Coord.class EnumArray2.java Offsetable.java
ArrayEnum.java EnumArray1.java EnumArray3.java
sh-4.1$ : First the Java file that _does_ work.
sh-4.1$ cat ArrayEnum.java
enum Coord { X_LFT, Y_LFT, X_RHT, Y_RHT }

public class ArrayEnum
{
String[] arrEnm;

public ArrayEnum ()
{
arrEnm = new String[ Coord.values().length];
}

public void set ( Coord index
, String element)
{
arrEnm[ index.ordinal()] = element;
}

public String get ( Coord index)
{
return arrEnm[ index.ordinal()];
}

public static void main ( String[] arguments)
{
if (0 < arguments.length && arguments.length % 2 == 0)
{ ArrayEnum demo = new ArrayEnum();
Coord[] allCoords = Coord.values();
Coord chosen;
int index;
for (Coord enm : Coord.values())
{ demo.set( enm, enm + "_orig_value");
}
System.out.println( "Before setting values:");
for (Coord enm : Coord.values())
{ System.out.println
( "demo.get( " + enm + ") == \"" + demo.get( enm) + "\".");
}
for (int arg = 0; arg < arguments.length; arg += 2)
{ index = -1;
for (;
{ if (++index == allCoords.length)
{ chosen = null;
break;
}
if (arguments[ arg].toUpperCase().equals( "" +
allCoords[ index]))
{ chosen = allCoords[ index];
break;
}
}
if (chosen != null)
{ System.out.println
( "demo.set( " + chosen + ", \"" + arguments[ arg + 1] +
");");
demo.set( chosen, arguments[ arg + 1]);
}
else
{ System.out.println
( "Couldn't match argument \"" + arguments[ arg]
+ "\" with a <Coord>
value!");
}
}
System.out.println( "After setting values:");
for (Coord enm : Coord.values())
{ System.out.println
( "demo.get( " + enm + ") == \"" + demo.get( enm) + "\".");
}
}
else
{ System.out.println( "Usage is");
System.out.println( " java ArrayEnum (<coord> <accompanying-
string>)+");
}
}
}
sh-4.1$ : I compile it.
sh-4.1$ javac ArrayEnum.java
sh-4.1$ : It compiles without error messages, so I run it with some
values.
sh-4.1$ java ArrayEnum x_rht Kevin x_lft Sandy y_rht Joshua
Before setting values:
demo.get( X_LFT) == "X_LFT_orig_value".
demo.get( Y_LFT) == "Y_LFT_orig_value".
demo.get( X_RHT) == "X_RHT_orig_value".
demo.get( Y_RHT) == "Y_RHT_orig_value".
demo.set( X_RHT, "Kevin);
demo.set( X_LFT, "Sandy);
demo.set( Y_RHT, "Joshua);
After setting values:
demo.get( X_LFT) == "Sandy".
demo.get( Y_LFT) == "Y_LFT_orig_value".
demo.get( X_RHT) == "Kevin".
demo.get( Y_RHT) == "Joshua".
sh-4.1$ : Then the three attempts at generic implementations, with the
sh-4.1$ : compilation error messages that accompanied them.
sh-4.1$ cat EnumArray1.java
import java.util.Iterator;

public class EnumArray1< Ty, En extends Enum< En>> implements Iterator
{
Ty[] enumArray;
En nextToRead;

public EnumArray1 ()
{
En[] vlues = En.values();
enumArray = new Ty[ vlues.length];
nextToRead = 0 < vlues.length ? vlues[ 0] : null;
}

public Ty get ( En index)
{
return enumArray[ index.ordinal()];
}

public void set ( En index
, Ty vlue)
{
enumArray[ index.ordinal()] = vlue;
}

public int size ()
{
return enumArray.length;
}

public boolean last ( En enm)
{
return enm.ordinal() + 1 == enumArray.length;
}

public boolean first ( En enm)
{
return enm.ordinal() == 0;
}

public En succ ( En enm)
{
int index = enm.ordinal() + 1;
return index < enumArray.length ? En.values()[ index] : null;
}

public En pred ( En enm)
{
int index = enm.ordinal() - 1;
return 0 <= index ? En.values()[ index] : null;
}

public boolean hasNext()
{
return nextToRead != null;
}

public Object next ()
{
Object nxtEnm = (Object) nextToRead;
nextToRead = next( nextToRead);
return nxtEnm;
}

public void remove ()
{
}
}
sh-4.1$ javac EnumArray1.java
EnumArray1.java:10: cannot find symbol
symbol : method values()
location: class java.lang.Enum<En>
En[] vlues = En.values();
^
EnumArray1.java:11: generic array creation
enumArray = new Ty[ vlues.length];
^
EnumArray1.java:44: cannot find symbol
symbol : method values()
location: class java.lang.Enum<En>
return index < enumArray.length ? En.values()[ index] : null;
^
EnumArray1.java:50: cannot find symbol
symbol : method values()
location: class java.lang.Enum<En>
return 0 <= index ? En.values()[ index] : null;
^
EnumArray1.java:61: next() in EnumArray1<Ty,En> cannot be applied to
(En)
nextToRead = next( nextToRead);
^
5 errors
sh-4.1$ cat EnumArray2.java
import java.util.Iterator;

public class EnumArray2< Ty, En extends Enum< En>> implements Iterator
{
Object[] enumArray;
En nextToRead;

public EnumArray2 ()
{
En[] vlues = En.values();
enumArray = new Object[ vlues.length];
nextToRead = 0 < vlues.length ? vlues[ 0] : null;
}

public Ty get ( En index)
{
return (Ty) enumArray[ index.ordinal()];
}

public void set ( En index
, Ty vlue)
{
enumArray[ index.ordinal()] = (Object) vlue;
}

public int size ()
{
return enumArray.length;
}

public boolean last ( En enm)
{
return enm.ordinal() + 1 == enumArray.length;
}

public boolean first ( En enm)
{
return enm.ordinal() == 0;
}

public En succ ( En enm)
{
int index = enm.ordinal() + 1;
return index < enumArray.length ? En.values()[ index] : null;
}

public En pred ( En enm)
{
int index = enm.ordinal() - 1;
return 0 <= index ? En.values()[ index] : null;
}

public boolean hasNext()
{
return nextToRead != null;
}

public Object next ()
{
Object nxtEnm = (Object) nextToRead;
nextToRead = next( nextToRead);
return nxtEnm;
}

public void remove ()
{
}
}
sh-4.1$ javac EnumArray2.java
EnumArray2.java:10: cannot find symbol
symbol : method values()
location: class java.lang.Enum<En>
En[] vlues = En.values();
^
EnumArray2.java:44: cannot find symbol
symbol : method values()
location: class java.lang.Enum<En>
return index < enumArray.length ? En.values()[ index] : null;
^
EnumArray2.java:50: cannot find symbol
symbol : method values()
location: class java.lang.Enum<En>
return 0 <= index ? En.values()[ index] : null;
^
EnumArray2.java:61: next() in EnumArray2<Ty,En> cannot be applied to
(En)
nextToRead = next( nextToRead);
^
Note: EnumArray2.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
4 errors
sh-4.1$ cat EnumArray3.java
import java.util.Iterator;

public class EnumArray3< Ty, En extends Offsetable, Enum> implements
Iterator
{
private static class Associated
{
Offsetable value;
Object element;

Associated ( Offsetable enm)
{ value = enm;
}
}

final En INIT_VALUE;
Associated[] enumArray;
En nextToRead;

private void fillValues ( Offsetable enm
, int index)
{
try
{ fillValues( enm.offsetBy( 1), index + 1);
}
catch (ArrayIndexOutOfBoundsException excptn)
{ enumArray = new Associated[ index + 1];
}
enumArray[ index] = new Associated( enm);
}

public EnumArray3 ( En initialValue)
{
INIT_VALUE = initialValue;
nextToRead = initialValue;
fillValues( (Offsetable) initialValue, 0);
}

public Ty get ( En index)
{
return (Ty) enumArray[ index.ordinal()].element;
}

public void set ( En index
, Ty vlue)
{
enumArray[ index.ordinal()].element = (Object) vlue;
}

public int size ()
{
return enumArray.length;
}

public boolean last ( En enm)
{
return enm.ordinal() + 1 == enumArray.length;
}

public boolean first ( En enm)
{
return enm.ordinal() == 0;
}

public boolean hasNext()
{
return nextToRead != null;
}

public Object next ()
{
Object nxtEnm = (Object) nextToRead;
nextToRead = nextToRead.offsetBy( 1);
return nxtEnm;
}

public void remove ()
{
}
}
sh-4.1$ javac EnumArray3.java
EnumArray3.java:40: cannot find symbol
symbol : method ordinal()
location: interface Offsetable
return (Ty) enumArray[ index.ordinal()].element;
^
EnumArray3.java:46: cannot find symbol
symbol : method ordinal()
location: interface Offsetable
enumArray[ index.ordinal()].element = (Object) vlue;
^
EnumArray3.java:56: cannot find symbol
symbol : method ordinal()
location: interface Offsetable
return enm.ordinal() + 1 == enumArray.length;
^
EnumArray3.java:56: operator + cannot be applied to
Offsetable.ordinal,int
return enm.ordinal() + 1 == enumArray.length;
^
EnumArray3.java:56: incomparable types: <nulltype> and int
return enm.ordinal() + 1 == enumArray.length;
^
EnumArray3.java:61: cannot find symbol
symbol : method ordinal()
location: interface Offsetable
return enm.ordinal() == 0;
^
EnumArray3.java:72: incompatible types
found : Offsetable
required: En
nextToRead = nextToRead.offsetBy( 1);
^
Note: EnumArray3.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
7 errors
sh-4.1$ exit
exit

Script done on Tue Aug 16 06:50:57 2011
 
Reply With Quote
 
 
 
 
Tom Anderson
Guest
Posts: n/a
 
      08-16-2011
On Tue, 16 Aug 2011, KevinSimonson wrote:

> Java is a pretty handy language in its own right. But in Ada one could
> define arrays to be indexed by enumerated types. Can Java do that?


No.

> If not, why not?


Because in Java, arrays are indexed by integers, and values of enumerated
types are objects (which are not integers).

As Patricia has pointed out, there is EnumMap. And your code below is not
too far off doing the same thing.

> sh-4.1$ javac EnumArray1.java
> EnumArray1.java:10: cannot find symbol
> symbol : method values()
> location: class java.lang.Enum<En>
> En[] vlues = En.values();


Every enum type has a static values() method, but you can't call static
methods polymorphically like this. In fact, i don't think you can call
static methods on type variables at all, although i could be wrong.

However, the Class class does have a getEnumConstants() methods which does
what you want. If the constructor takes a suitable instance of Class, it
can use that method.

> EnumArray1.java:11: generic array creation
> enumArray = new Ty[ vlues.length];
> ^


An annoying consequence of Java's approach to generics (type erasure) is
that you can't create arrays of a generic type. But if you have a Class
object for the component type, you can use java.lang.reflect.Array's
newInstance method to create one.

> EnumArray1.java:61: next() in EnumArray1<Ty,En> cannot be applied to
> (En)
> nextToRead = next( nextToRead);
> ^


There is no single-argument method called next in your code.

Here's an implementation of the constructor which might work (barring a
bit of try-catch around the reflection):

public EnumArray1(Class<En> type) {
En[] values = type.getEnumConstants();
enumArray = Array.newInstance(type, values.length);
nextToRead = values[0];
}

I've dispensed with the length check, because if someone passes in an
empty enum, then as far as i'm concerned, they deserve the
ArrayIndexOutOfBoundsException they'll get.

I haven't gone over your other classes, because hopefully this should
solve all your problems.

Note that the constructor i suggest is used like this:

EnumArray1<RockPaperScissors> rps = new EnumArray1<RockPaperScissors>(RockPaperScissors.cl ass);

Which is a bit annoying. If you are very annoyed, and if you are prepared
to stomach some reflective witchcraft, you can add another, more magical,
constructor:

protected EnumArray1() {
this((Class<En>)((ParameterizedType)getClass().get GenericSuperclass()).getActualTypeArguments()[0]);
}

Which lets you then write a more magical but briefer construction
expression:

EnumArray1<RockPaperScissors> rps = new EnumArray1<RockPaperScissors>() {};

I would suggest, though, that you don't.

tom

--
Freedom, Beauty, Truth, and Love!
 
Reply With Quote
 
 
 
 
Gene Wirchenko
Guest
Posts: n/a
 
      08-16-2011
On Tue, 16 Aug 2011 07:53:38 -0700 (PDT), KevinSimonson
<(E-Mail Removed)> wrote:

>Ada, the programming language mandated for the military for a time,
>was a wonderful language that didn't deserve to die. But it did, and
>now Java is alive and well and nobody seems to be doing anything at
>all with Ada.
>
>Java is a pretty handy language in its own right. But in Ada one
>could define arrays to be indexed by enumerated types. Can Java do
>that? If not, why not?


I do not know if this is relevant for you, but C# apparently can.
It involves redefinition of []. I coded a simple case of "one",
"two", and "three" each setting/getting the respective array element
and anything else getting/getting element 0. I assume that an enum
value would work, too.

[snip]

Sincerely,

Gene Wirchenko
 
Reply With Quote
 
Arne Vajh°j
Guest
Posts: n/a
 
      08-17-2011
On 8/16/2011 10:53 AM, KevinSimonson wrote:
> Ada, the programming language mandated for the military for a time,
> was a wonderful language that didn't deserve to die. But it did, and
> now Java is alive and well and nobody seems to be doing anything at
> all with Ada.
>
> Java is a pretty handy language in its own right. But in Ada one
> could define arrays to be indexed by enumerated types. Can Java do
> that? If not, why not?


Java is a simpler language than Ada. In Java array indexes are
int and you have byte/short/int/long types and that is it.

You will need to either use values 0..n-1 as array indexes or
switch to one of the Map data types in java.util.

Arne

 
Reply With Quote
 
Arne Vajh°j
Guest
Posts: n/a
 
      08-17-2011
On 8/16/2011 5:54 PM, Gene Wirchenko wrote:
> On Tue, 16 Aug 2011 07:53:38 -0700 (PDT), KevinSimonson
> <(E-Mail Removed)> wrote:
>> Ada, the programming language mandated for the military for a time,
>> was a wonderful language that didn't deserve to die. But it did, and
>> now Java is alive and well and nobody seems to be doing anything at
>> all with Ada.
>>
>> Java is a pretty handy language in its own right. But in Ada one
>> could define arrays to be indexed by enumerated types. Can Java do
>> that? If not, why not?

>
> I do not know if this is relevant for you, but C# apparently can.
> It involves redefinition of []. I coded a simple case of "one",
> "two", and "three" each setting/getting the respective array element
> and anything else getting/getting element 0. I assume that an enum
> value would work, too.


[] in C# can be either array index or using a so called
indexer of a class.

But it is either one or the other or not defined - it is
never redefined.

Arne
 
Reply With Quote
 
Arne Vajh°j
Guest
Posts: n/a
 
      08-17-2011
On 8/16/2011 8:52 PM, markspace wrote:
> On 8/16/2011 5:38 PM, Arne Vajh°j wrote:
>> Java is a simpler language than Ada. In Java array indexes are
>> int and you have byte/short/int/long types and that is it.

>
> Er, all primitives. I.e., add char/float/double and references to that.


Sorry.

byte/short/int/long integer types

Point being that you don't have 1900..2011 and similar.

Arne



 
Reply With Quote
 
markspace
Guest
Posts: n/a
 
      08-17-2011
On 8/16/2011 6:56 PM, Arne Vajh°j wrote:
> byte/short/int/long integer types


OK, you mean for indexes? char works too, and long really doesn't -- it
has to be cast to an int. For longs, Java recognizes the loss of
precision using long and requires that you acknowledge that the upper
bits will simply be truncated.


 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      08-17-2011
On Tuesday, August 16, 2011 8:20:05 PM UTC-7, markspace wrote:
> On 8/16/2011 6:56 PM, Arne Vajh´┐Żj wrote:
> > byte/short/int/long integer types

>
> OK, you mean for indexes? char works too, and long really doesn't -- it
> has to be cast to an int. For longs, Java recognizes the loss of
> precision using long and requires that you acknowledge that the upper
> bits will simply be truncated.


JLS 10:
"The variables contained in an array have no names; instead they are referenced by array access expressions that use nonnegative integer index values."

IOW, you never index arrays with a byte, char or short. If you try, you get a widening conversion first, and if that results in a negative int value,you got problems.

--
Lew
 
Reply With Quote
 
Niklas Holsti
Guest
Posts: n/a
 
      08-17-2011
KevinSimonson wrote:
> Ada, the programming language mandated for the military for a time,
> was a wonderful language that didn't deserve to die. But it did,


No it didn't. The Ada language has been extended and updated regularly;
a new standard is due to appear in 2012. Several compilers are
available, one of the best being gnat, which is a part of gcc and is
freely available on many platforms. See libre.adacore.com and
http://en.wikipedia.org/wiki/Ada_(programming_language).

> and now Java is alive and well


Agreed.

> and nobody seems to be doing anything at all with Ada.


The number of people working with Ada is certainly smaller than for
Java, but far from zero. Even the USENET group comp.lang.ada is quite
active.

--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
 
Reply With Quote
 
Arved Sandstrom
Guest
Posts: n/a
 
      08-17-2011
On 11-08-17 12:45 AM, Lew wrote:
> On Tuesday, August 16, 2011 8:20:05 PM UTC-7, markspace wrote:
>> On 8/16/2011 6:56 PM, Arne Vajh´┐Żj wrote:
>>> byte/short/int/long integer types

>>
>> OK, you mean for indexes? char works too, and long really doesn't -- it
>> has to be cast to an int. For longs, Java recognizes the loss of
>> precision using long and requires that you acknowledge that the upper
>> bits will simply be truncated.

>
> JLS 10:
> "The variables contained in an array have no names; instead they are referenced by array access expressions that use nonnegative integer index values."
>
> IOW, you never index arrays with a byte, char or short. If you try, you get a widening conversion first, and if that results in a negative int value, you got problems.
>

I'm feeling slow this morning: how do we get problems with byte->int,
short->int, or char->int again? These are all integral widening
primitive conversions, respectively

byte->int: 8-bit signed 2's complement (2C) -> 32-bit signed 2C,
short->int: 16-bit signed 2C -> 32-bit signed 2C
char->int: 16-bit unsigned -> 32-bit signed 2C

According to common sense and the JLS, all three of these conversions
_exactly_ preserve the original value. How could they not?

AHS
 
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
How To Name Enumerated Types and Structs Immortal Nephi C++ 4 08-24-2010 05:20 PM
Assigning Values to Enumerated Types Kevin Neilson VHDL 9 05-09-2008 05:19 PM
size of a class having enumerated data types? ypjofficial@indiatimes.com C++ 8 01-23-2006 12:29 PM
Progressive restriction on enumerated types in Owl David R. Throop XML 0 05-05-2005 11:39 PM
strange recursivion with enumerated types - how is this possible? rfractal30 Java 6 02-25-2005 02:38 AM



Advertisments