Beef with Enums

I was very grateful back in Java 5 to see that they'd given the language enums, but it's always been a source of aggravation to me that they don't really seem that compatible with interfaces.

For example, now that a lot of Java components have a setComponentPopupMenu method, I've had my context-sensitive popup menus implement an interface, e.g:

publicinterface ListPopup

{

publicvoid buildPopupContext(int context);

}

where the parameter context would be an old-style enum (public static final int).

Now, there are several problems I'm encountering with the new enums:

1. A typical buildPopupContext() method would switch over the context, so if I implement the interface as

publicvoid buildPopupContext(Enum context)

then I can't use switch statements. I know everyone will be like "OMFG. Use if-else!," but ******, I like my switch statements!

Or, I could implement my interface as generic, with some sort of enum in a superclass as follows:

/**

*Interface

*/

publicinterface ListPopup<Textends AbstractList>

{

publicvoid buildPopupContext(T.ListContext context);

}

/**

*Enum in AbstractListPopup

*/

publicabstractclass AbstractListPopup<Textends JXList>

extends JPopupMenuimplements ListPopup

{

publicenum ParsingListContext

{

ITEM_SELECTED,

ITEM_UNSELECTED;

}

}

/**

*Subclass of AbstractListPopup

*/

publicclass RssListPopupextends AbstractListPopup<RssDisplayList>

{

publicenum ParsingListContext

{

ITEM_SELECTED,

ITEM_UNSELECTED,

NOTHING_SELECTED;

}

publicvoid buildPopupContext(ParsingListContext context)

{

switch(context)

{

case ITEM_SELECTED :

{

//stuff

break;

}

}

}

Now, it's not always clear to me that the ParsingListContext the buildPopupContext wants to use is the one in the superclass because that interface is implemented in that class. To use the correct (sort of overridden enum), the non-abstract class must implement the ListPopup interface, as opposed to the superclass. I realize that there are bajillions of ways around this (use old-style enums with all their problems, implement the interface on the subclass using the correct generic identifier, declare the method abstract in the superclass instead of using an interface, etc.), but all of these seem a bit reminiscent of C++'s complexity, and the traditional Java elegance seems a bit lacking.

Any comments? How do you guys use enums in conjunction with interfaces?

Joe

P.S.

I threw together these examples off of a project I'm working on, but I don't have any sort of development tools on this computer, so there may be errors, etc. that I'm missing. Don't hesitate to point these out!

[4526 byte] By [Joe_ha] at [2007-11-27 11:20:55]
# 1

You can indeed switch on enums. Try it

georgemca at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 2

You can switch on enums, but not Enums. The only way I've found of passing enums to a method is to use that enum's identifier. In an interface, presumably, the method should be as generic as possible, but it's not possible to pass a method a straight enum.

Ex.

public void switchEnum(enum sw) //Woops. Doesn't want to compile

{

}

public void switchEnum(Enum sw)

{

switch(sw) //Whoops. Enum's an object wrapper-class. Can't switch it!

{

}

}

or

[code]

Proper way:

[code]

public enum e { Item1, Item2 }

public void switchEnum(e para)

{

switch(e)

{

case Item1 :

///stuff

}

}

or

public void switchEnum(Enum e)

{

switch (e.ordinal())

{

case (Item1.ordinal()) :

}

}

Still doesn't feel quite right to me :/

Joe

Joe_ha at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 3

Huh?

public class EnumSwitch {

enum MyEnum {

FIRST,

SECOND,

THIRD

}

public static void main(String[] args) {

MyEnum e = MyEnum.FIRST;

switch(e) {

case FIRST:

System.err.println("First");

break;

case SECOND:

System.err.println("Second");

break;

case THIRD:

System.err.println("Third");

}

}

}

What were you trying to do? Switch on a variety of disparate enums with one switch/case? Sounds like a smelly design, to me. To what end?

georgemca at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 4

If I read right, you want to switch on a bunch of different types. Not very OO! Rather than making decisions on what to do based on what object comes through a method, why can't that object carry the correct behaviour with it? Switch/case, ifs, any conditional logic, can often be avoided altogether by using polymporphism

What is the actual thing you're trying to achieve here?

georgemca at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 5

The problem isn't that apparent when you're only using the enums in the same class as the method that switches them.

public class EnumDemonstration

{

public EnumDemonstration()

{

}

public enum menuContext

{

ITEM_SELECTED,

NOTHING_SELECTED

}

public void buildContext(Enum e)

{

switch(e.ordinal())

{

case menuContext.ITEM_SELECTED :

{

//stuff

}

}

}

}

//Different class

public class testEnum

{

private EnumDemonstration dem = new EnumDemonstration();

dem.buildContext(EnumDemonstration.menuContext.ITEM_SELECTED);

}

Feels clumsy and unintuitive. I dunno, maybe it's not as bad as I'm making it out to be.

Joe

Joe_ha at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 6

Frankly, I would love to build a popupmenu that automatically detects the context using some weird voodoo magic. I don't know how to do that though, without having the parent component pass it the context.

Joe.

And you're absolutely right. It doesn't feel very OO

Joe_ha at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 7

Still not sure what your actual problem is. It appears to be that you're annoyed about having to qualify the name of an enum with it's enclosing type. No big deal that!

Looking at the larger picture, this context menu stuff, I don't think static definitions for the context is the best way forward anyway

georgemca at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 8

The problem seems slightly worse than I thought.

Oh, and George, sorry I didn't clarify the problem. The problem is with interfaces containing methods that are passed some sort of enumeration as a parameter.

I'd like a very generic interface containing one method: the buildPopupContext method.

e.g.

public interface ListPopup

{

public void buildPopupContext(Enum context);

}

but the problem is, in one of its implementing classes:

public void buildPopupContext(Enum context)

{

switch(context.ordinal())

{

case menuContext.ITEM_SELECTED.ordinal() : //error see below

{

}

}

/*

*Error: \parsing\lists\RssParsingListPopup.java:56:

* constant expression required

*case menuContext.ITEM_SELECTED.ordinal() :

*/

}

Anyway, very generic (generalized) interfaces that contain methods with enums as parameters seem to me to have some problems.

Joe

Joe_ha at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 9

>

>Looking at the larger picture, this context menu stuff, I don't think static >definitions for the context is the best way forward anyway.

I'm just a hobbyist, I've never had any classes on Java GUI programming. I have books, but none that say -anything- about context-sensitive popup menus. I would -love- a better way to do things.

Joe

Joe_ha at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 10

> >

> >Looking at the larger picture, this context menu

> stuff, I don't think static >definitions for the

> context is the best way forward anyway.

>

> I'm just a hobbyist, I've never had any classes on

> Java GUI programming. I have books, but none that

> say -anything- about context-sensitive popup menus.

> I would -love- a better way to do things.

>

> Joe

Well, in all fairness, why should they? I've got loads of books, and none of them say anything about applying NHS-funded discounts to the gross cost of a contact lens scheme, but we still managed to figure it out! The point I'm making is, a book will show you how to generate a popup menu, but it's up to you to decide how to use that. "Context-sensitive" is your own requirement. Enums, I don't think, are the best solution for this. You're asking for extra maintenance every time you add a feature.

Your app. can find out where a right-click event comes from, that is the start of your context

georgemca at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 11

To digress only slightly, I realize that in general, books should contain generalized concepts, rather than specific solutions. This happens to be a solution that I've found works for components with limited possibilities for popups.

The issue here is not whether or not I've found the best possible solution to my problem, it's whether or not enumerated types are compatible with interfaces in a meaningful way. If people have found meaningful ways of using interfaces in conjunction with enumerated types, I would like to hear about them, as all the solutions I've found feel ugly.

Joe_ha at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 12

> To digress only slightly, I realize that in general,

> books should contain generalized concepts, rather

> than specific solutions. This happens to be a

> solution that I've found works for components with

> limited possibilities for popups.

>

> The issue here is not whether or not I've found the

> best possible solution to my problem, it's whether or

> not enumerated types are compatible with interfaces

> in a meaningful way. If people have found meaningful

> ways of using interfaces in conjunction with

> enumerated types, I would like to hear about them, as

> all the solutions I've found feel ugly.

We use enums to represent a bunch of string constants, such as labels for buttons, but our software is mutli-lingual (as opposed to might be, lets code for it in case) so the enums come in handy for swapping sets of strings in different languages in. Now, there are thousands of these things in our system, applicable to different parts of the domain, so we can't have just one huge enum. What we have, is an interface called TextToken, with one method on - getText() - which all these enums implement. The actuyal text values are loaded from property files at runtime, but we code to these TextToken enums via this interface

georgemca at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 13

Why not create a marker interface for the enums you want to switch on?

Something like:interface ContextEnum {}

interface ListPopup<T extends ContextEnum> {

void buildPopupContext(T context);

}

enum FooContext implements ContextEnum {

ITEM_SELECTED,

}

class Foo implements ListPopup<FooContext> {

public void buildPopupContext(FooContext context) {

switch (context) {

case ITEM_SELECTED:

// do stuff

break;

}

}

}

dwga at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 14

You should not be using the Enum class (Capital E), enum should get what you want done.

You can create a file and just put a public enum in it, this will solve your discomfort with having to use an enum in multiple classes.

IE:

Orientation.java

public enum Orientation {

VERTICAL,

HORIZONTAL,

TOP,

BOTTOM

}

You can use it in any class that imports it, and just say

Orientation.TOP

and not

containingClass.Orientation.TOP

robtafta at 2007-7-29 14:45:27 > top of Java-index,Java Essentials,Java Programming...
# 15

Hmm. Actually, that works very nicely! To be honest, I didn't know enums could implement interfaces.

Thanks for the great tip!

Joe

Joe_ha at 2007-7-29 14:45:32 > top of Java-index,Java Essentials,Java Programming...
# 16

> Hmm. Actually, that works very nicely! To be

> honest, I didn't know enums could implement

> interfaces.

Enums are compiled to normal classes that extend Enum. That's why they can't extend any other classes, but Java has always had multiple inheritance when it comes to interfaces.

But I have to agree with others here that have said that you should try to avoid switching at all, why not have the respective enums handle the context building.

dwga at 2007-7-29 14:45:32 > top of Java-index,Java Essentials,Java Programming...
# 17

> > Hmm. Actually, that works very nicely! To be

> > honest, I didn't know enums could implement

> > interfaces.

>

> Enums are compiled to normal classes that extend

> Enum. That's why they can't extend any other classes,

> but Java has always had multiple inheritance when it

> comes to interfaces.

>

> But I have to agree with others here that have said

> that you should try to avoid switching at all, why

> not have the respective enums handle the context

> building.

I say "why have the enums at all?". As new contexts are added, the enum has to be changed again, and someone has to remember to do it

georgemca at 2007-7-29 14:45:32 > top of Java-index,Java Essentials,Java Programming...