use case for extending enum, but this is not possible in java

Discussion in 'Java' started by Laura Schmidt, Jun 15, 2014.

  1. Hi,

    I have found a need to extend enum, but this is not possible in java.
    Take a look at the situation:

    In an application, there is an enum ListCommand that enumerates the
    commands a user may execute on list entries:

    public enum ListCommand
    {
    OPEN,
    EDIT,
    DELETE;
    }

    There is an interface that uses this enum:

    public interface ListCommandProcessor
    {
    void onListCommand (ListCommand cmd);
    }

    And there is a generic Listing class that is used to show customized
    lists in the GUI and which uses the above interface:

    public class Listing<T>
    {
    ...
    ListCommandProcessor processor;
    ...
    }

    So far, so good.

    Now I am making a cut: The generic class Listing<T> should be moved into
    a generic java library, so that it can be used by different
    applications. So I also need to move the interface ListCommandProcesor
    into this library, and this would implicate that I also move the enum
    ListCommand into the library. But the enum ListCommand ist application
    specific. If I move it to the library, it must be extendable somehow. If
    there were no limitations in the java language, I would separate the
    concerns of library and application like this:

    --- library:

    public enum ListCommand
    {
    // empty at library level
    }

    public interface ListCommandProcessor
    {
    void onListCommand (ListCommand cmd);
    }

    --- application:

    public enum AppListCommand extends ListCommand
    {
    OPEN,
    CLOSE,
    SOMETHINGSPECIAL;
    }

    public class MyApp extends ListCommandProcessor
    {
    ...
    Listing<XYZ> listing = new Listing<XYZ> ();
    listing.setProcessor (this);

    public void onListCommand (ListCommand cmd)
    {
    AppListCommand c = (AppListCommand) cmd;

    switch (c)
    {
    ...
    }
    }
    }

    This would be my solution, but it is not possible in java to extend
    enums. But I need to make a cut somewhere in order to move Listing<T>
    into the generic library. The only solution I can imagine is to change

    onListCommand (ListCommand cmd);

    into

    onListCommand (int cmd);

    But then I would loose the beautiful type binding and I will soon find
    myself defining list commands like it was done in the 90's in C:

    public static final int CMD_OPEN = 1;
    public static final int CMD_EDIT = 2;
    public static final int CMD_DELETE = 3;
    public static final int CMD_SOMETHINGSPECIAL = 55;

    I know that this would be a way out, but I want to make sure that there
    is no better solution.

    How would you do this?

    Thank you,
    Laura
     
    Laura Schmidt, Jun 15, 2014
    #1
    1. Advertisements

  2. Laura Schmidt

    Stefan Ram Guest

    Laura Schmidt <> writes:
    >ListCommand into the library. But the enum ListCommand ist application
    >specific. If I move it to the library, it must be extendable somehow. If


    The members of an enumeration are static AFAIK.

    I see two possibilities:

    1. Use a dynamic collection (like java.util.Set<java.lang.String>)
    instead of an enum.

    2. Don't put application-dependent (AD) code into a
    library that is intended to be an
    application-independent (AI) library. If class
    Listing<T> is large, you can split it into an AI part and
    an AD part (which sometimes requires some skill and
    patterns), then you can move the AI part into the AI library,
    while the AD part needs to be in each application.

    3. If you absolutely insist, you could put code into the
    library that will generate the class file (byte code)
    for the enum at run time.
     
    Stefan Ram, Jun 15, 2014
    #2
    1. Advertisements

  3. On 15/06/14 00:24, Laura Schmidt wrote:
    > In an application, there is an enum ListCommand that enumerates the
    > commands a user may execute on list entries:
    >
    > public enum ListCommand
    > {
    > OPEN,
    > EDIT,
    > DELETE;
    > }
    >
    > There is an interface that uses this enum:
    >
    > public interface ListCommandProcessor
    > {
    > void onListCommand (ListCommand cmd);
    > }
    >
    > And there is a generic Listing class that is used to show customized
    > lists in the GUI and which uses the above interface:
    >
    > public class Listing<T>
    > {
    > ...
    > ListCommandProcessor processor;
    > ...
    > }
    >
    > So far, so good.
    >
    > Now I am making a cut: The generic class Listing<T> should be moved
    > into a generic java library, so that it can be used by different
    > applications. So I also need to move the interface ListCommandProcesor
    > into this library, and this would implicate that I also move the enum
    > ListCommand into the library. But the enum ListCommand ist application
    > specific. If I move it to the library, it must be extendable somehow.


    Does your Listing class demand anything of ListCommand? Does it even
    require it to be an enum? If not, does this help?:

    // In library
    public interface Processor<E> {
    void onListCommand(E cmd); // inappropriate name now?
    }

    public class Listing<T, E> {
    Processor<E> processor;
    public void setProcessor(Processor<E> processor) {
    this.processor = processor;
    }
    }

    // In application
    public enum AppListCommand {
    OPEN, CLOSE, STUFF;
    }

    public class MyApp extends Processor<AppListCommand> {
    {
    Listing<XYZ, AppListCommand> listing = ...;
    listing.setProcessor(this);
    }

    public void onListCommand(AppListCommand cmd) {
    switch (cmd) { ... }
    }
    }

    Depending on unspecified factors, you might be able to use Processor<?
    super E>, or have to use Listing<T, E extends Enum<E>>.

    --
    ss at comp dot lancs dot ac dot uk
     
    Steven Simpson, Jun 15, 2014
    #3
  4. On 15.06.14 01.24, Laura Schmidt wrote:
    > In an application, there is an enum ListCommand that enumerates the
    > commands a user may execute on list entries:
    >
    > public enum ListCommand
    > {
    > OPEN,
    > EDIT,
    > DELETE;
    > }
    >
    > There is an interface that uses this enum:
    >
    > public interface ListCommandProcessor
    > {
    > void onListCommand (ListCommand cmd);
    > }

    [...]
    > public enum AppListCommand extends ListCommand
    > {
    > OPEN,
    > CLOSE,
    > SOMETHINGSPECIAL;
    > }


    I wished something like that in other languages too. However, things are
    not that easy as they appear. We had a similar discussion in the C++
    group some time ago.

    Extending a class means that you provide all the functionality of the
    base class and anyone that can accept the base can deal with your
    extension as well. But this does not hold true in your case.
    What should a method accepting the base enum do when it receives an
    unexpected value outside the range of the declared enum type? Note that
    this is the other way around than for overridden methods. With methods
    you call the overridden method with the parameters of definition in the
    base class. What you expect is, that a method, that takes the base enum
    parameters is called with parameters of your derived enum. It is like
    covariance versus contravariance. You may always pass a refined type as
    argument, but you can only receive a more general type than declared
    from the return value. The /value/ of your enum is more like the return
    value. So an instance taking the larger number of constants may also
    store the values of the base enum, i.e. a method that can deal with the
    extended enum may safely be called with the base enum type, but not the
    other way around.


    > This would be my solution, but it is not possible in java to extend
    > enums.


    Your requirements requires runtime polymorphism. Enums are not
    polymorphic. In no language that I know of.


    > But I need to make a cut somewhere in order to move Listing<T>
    > into the generic library. The only solution I can imagine is to change


    > onListCommand (ListCommand cmd);
    >
    > into
    >
    > onListCommand (int cmd);
    >
    > But then I would loose the beautiful type binding and I will soon find
    > myself defining list commands like it was done in the 90's in C:


    > public static final int CMD_OPEN = 1;
    > public static final int CMD_EDIT = 2;
    > public static final int CMD_DELETE = 3;
    > public static final int CMD_SOMETHINGSPECIAL = 55;


    You can always use strong typing by wrapping the ints with a class.
    You may also drop the int entirely and use instance equality instead.
    This is approximately the way enums work in Java. They are basically
    syntactic sugar.

    class ListCommand
    {
    protected ListCommand();

    public static final ListCommand CMD_OPEN = new ListCommand();
    ...

    public ListCommand[] values()
    { return ...
    }
    }

    If you are smart enough to replace the ListCommand constructor calls by
    a private factory, then you might build the values array without
    repeating yourself in the values method.

    Note that you need to override values() in each derived class. It must
    extend super.values() by it's own additions.


    Of course, the java language could have implemented the enums this way
    unless you declare them final. But because of the pitfalls above and
    maybe because in 99% of the use cases enums are not polymorphic, they
    have chosen to make them final by default.


    Marcel
     
    Marcel Müller, Jun 15, 2014
    #4
  5. Laura Schmidt

    markspace Guest

    On 6/14/2014 4:24 PM, Laura Schmidt wrote:

    > public void onListCommand (ListCommand cmd)
    > {
    > AppListCommand c = (AppListCommand) cmd;
    >
    > switch (c)
    > {
    > ...
    > }



    I have to agree with Marcel Muller here. Enums, the way you use them,
    are not polymorphic. And using a switch to emulate polymorphism is
    almost always a bad idea. See Replace Conditional with Polymorphism.

    http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html

    However you can fake it a bit in Java. Java enum are sorta-kinda
    polymorphic. (I think that's the technical term.)


    interface MyCommand {
    Object eval();
    }

    void onListCommand( MyCommand cmd ) {
    System.out.println( cmd.eval() );
    }

    public enum ListCommand implements MyCommand
    {
    OPEN,
    EDIT,
    DELETE;
    public Object eval() { return this.ordinal(); }
    }

    public enum AppListCommand implements MyCommand
    {
    OPEN,
    CLOSE,
    SOMETHINGSPECIAL() {
    public Object eval() { return "Hi";}};
    public Object eval() { return this.ordinal(); }
    }

    Not compiled or tested, although part was:

    public static void main( String[] args )
    {
    onListCommand( AppListCommand.OPEN, AppListCommand.CLOSE,
    AppListCommand.SOMETHINGSPECIAL );
    }
    private static void onListCommand( MyCommand... cmd )
    {
    for( MyCommand x : cmd ) {
    System.out.println( x.eval() );
    }
    }
    run:
    0
    1
    Hi
    BUILD SUCCESSFUL (total time: 1 second)
     
    markspace, Jun 15, 2014
    #5
  6. Laura Schmidt

    Stefan Ram Guest

    Laura Schmidt <> writes [some lines selected]:
    >there were no limitations in the java language, I would separate the
    >concerns of library and application like this:
    >--- library:
    >public enum ListCommand
    >public interface ListCommandProcessor
    > void onListCommand (ListCommand cmd);
    >--- application:
    >public enum AppListCommand extends ListCommand
    > OPEN,
    > CLOSE,
    > SOMETHINGSPECIAL;
    >public class MyApp extends ListCommandProcessor
    > listing.setProcessor (this);
    > public void onListCommand (ListCommand cmd)
    > AppListCommand c = (AppListCommand) cmd;
    >How would you do this?


    library;

    public class Command {}

    public interface CommandProcessor
    { void onCommand ( Command cmd ) ... }
    /* NB: The semantics are now actually /better/ than
    in the quoted fragments, because »cmd« is a /command/,
    not a »list command« as quoted above ! */

    public class OPEN extends Command { /* possibly: ... */ }
    /* NB: we have the inheritance semantics usually recommended,
    because »OPEN« /is a/ command! */

    public class CLOSE extends Command { /* possibly: ... */ }
    public class DELETE extends Command { /* possibly: ... */ }

    application:

    public class AppCommand extends Command { /* possibly: ... */ }

    public class SOMETHINGSPECIAL extends AppCommand { /* possibly: ... */ }

    public class MyApp extends CommandProcessor
    { ...
    listing.setProcessor( this );

    public void onCommand( final Command cmd )
    {
    AppCommand c =( AppCommand )cmd;
    /* this cast will fail when( cmd instanceof OPEN ),
    but this is correct, since OPEN /is not/ an AppCommand */ ... }}
     
    Stefan Ram, Jun 15, 2014
    #6
  7. On 15.06.2014 01:24, Laura Schmidt wrote:
    > Hi,
    >
    > I have found a need to extend enum, but this is not possible in java.
    > Take a look at the situation:
    >
    > In an application, there is an enum ListCommand that enumerates the
    > commands a user may execute on list entries:
    >
    > public enum ListCommand
    > {
    > OPEN,
    > EDIT,
    > DELETE;
    > }
    >
    > There is an interface that uses this enum:
    >
    > public interface ListCommandProcessor
    > {
    > void onListCommand (ListCommand cmd);
    > }
    >
    > And there is a generic Listing class that is used to show customized
    > lists in the GUI and which uses the above interface:
    >
    > public class Listing<T>
    > {
    > ...
    > ListCommandProcessor processor;
    > ...
    > }
    >
    > So far, so good.
    >
    > Now I am making a cut: The generic class Listing<T> should be moved into
    > a generic java library, so that it can be used by different
    > applications. So I also need to move the interface ListCommandProcesor
    > into this library, and this would implicate that I also move the enum
    > ListCommand into the library. But the enum ListCommand ist application
    > specific. If I move it to the library, it must be extendable somehow. If
    > there were no limitations in the java language, I would separate the
    > concerns of library and application like this:
    >
    > --- library:
    >
    > public enum ListCommand
    > {
    > // empty at library level
    > }
    >
    > public interface ListCommandProcessor
    > {
    > void onListCommand (ListCommand cmd);
    > }
    >
    > --- application:
    >
    > public enum AppListCommand extends ListCommand
    > {
    > OPEN,
    > CLOSE,
    > SOMETHINGSPECIAL;
    > }
    >
    > public class MyApp extends ListCommandProcessor
    > {
    > ...
    > Listing<XYZ> listing = new Listing<XYZ> ();
    > listing.setProcessor (this);
    >
    > public void onListCommand (ListCommand cmd)
    > {
    > AppListCommand c = (AppListCommand) cmd;
    >
    > switch (c)
    > {
    > ...
    > }
    > }
    > }
    >
    > This would be my solution, but it is not possible in java to extend
    > enums. But I need to make a cut somewhere in order to move Listing<T>
    > into the generic library. The only solution I can imagine is to change
    >
    > onListCommand (ListCommand cmd);
    >
    > into
    >
    > onListCommand (int cmd);
    >
    > But then I would loose the beautiful type binding and I will soon find
    > myself defining list commands like it was done in the 90's in C:
    >
    > public static final int CMD_OPEN = 1;
    > public static final int CMD_EDIT = 2;
    > public static final int CMD_DELETE = 3;
    > public static final int CMD_SOMETHINGSPECIAL = 55;
    >
    > I know that this would be a way out, but I want to make sure that there
    > is no better solution.
    >
    > How would you do this?


    To me this is pretty clear: ListCommandProcessor is an interface and
    needs an application specific implementation anyway to interpret the
    argument to onListCommand(). As you do not seem to define specific
    methods in ListCommand any implementation of onListCommand() is
    basically totally free to do what it needs to do with the argument and
    you do not have to constrain the argument type in any way. So you make
    it generic. So we have

    Library part:


    public class Listing<T,C> {
    ...
    private ListCommandProcessor<C> processor;
    ...
    }

    public interface ListCommandProcessor<C> {
    void onListCommand(C cmd);
    }


    Specific implementation:

    public class MyList {
    }

    public enum ListCommand {
    OPEN,EDIT,DELETE
    }

    public class MyApp implements ListCommandProcessor<ListCommand> {
    ...
    Listing<MyList,ListCommand> listing =
    new Listing<MyList,ListCommand> ();
    listing.setProcessor(this);

    public void onListCommand(ListCommand cmd)
    {
    switch (cmd) {
    ...
    }
    }
    }


    An alternative approach might be to remove ListCommandProcessor
    altogether and use a more OO approach by implementing functionality
    inside the ListCommand (what is an enum now but could be something else).

    Library part:

    public interface ListCommand<T> {
    void execute(T list);
    }

    public class Listing<T> {
    ...
    public void someMethod() {
    final T list = ...
    final ListCommand<T> cmd = ...
    cmd.execute(list);
    }
    ...
    }



    Specific implementation:

    public class MyList {
    }

    // this could be anything, not just an enum
    public enum MyListCommand implements ListCommandProcessor<MyList> {
    OPEN {
    @Override
    public void onListCommand(MyList cmd) {
    // whatever
    }
    },
    EDIT {
    @Override
    public void onListCommand(MyList cmd) {
    // whatever
    }
    }
    ...
    }

    Kind regards

    robert
     
    Robert Klemme, Jun 15, 2014
    #7
  8. On 15.06.2014 01:24, Laura Schmidt wrote:

    > I have found a need to extend enum, but this is not possible in java.
    > Take a look at the situation:
    >
    > In an application, there is an enum ListCommand that enumerates the
    > commands a user may execute on list entries:
    >
    > public enum ListCommand
    > {
    > OPEN,
    > EDIT,
    > DELETE;
    > }
    >
    > There is an interface that uses this enum:
    >
    > public interface ListCommandProcessor
    > {
    > void onListCommand (ListCommand cmd);
    > }
    >
    > And there is a generic Listing class that is used to show customized
    > lists in the GUI and which uses the above interface:
    >
    > public class Listing<T>
    > {
    > ...
    > ListCommandProcessor processor;
    > ...
    > }
    >
    > So far, so good.
    >
    > Now I am making a cut: The generic class Listing<T> should be moved into
    > a generic java library, so that it can be used by different
    > applications. So I also need to move the interface ListCommandProcesor
    > into this library, and this would implicate that I also move the enum
    > ListCommand into the library. But the enum ListCommand ist application
    > specific. If I move it to the library, it must be extendable somehow. If
    > there were no limitations in the java language, I would separate the
    > concerns of library and application like this:


    > How would you do this?


    To me this is pretty clear: ListCommandProcessor is an interface and
    needs an application specific implementation anyway to interpret the
    argument to onListCommand(). As you do not seem to define specific
    methods in ListCommand any implementation of onListCommand() is
    basically totally free to do what it needs to do with the argument and
    you do not have to constrain the argument type in any way. So you make
    it generic. So we have

    Library part:


    public class Listing<T,C> {
    ...
    private ListCommandProcessor<C> processor;
    ...
    }

    public interface ListCommandProcessor<C> {
    void onListCommand(C cmd);
    }


    Specific implementation:

    public class MyList {
    }

    public enum ListCommand {
    OPEN,EDIT,DELETE
    }

    public class MyApp implements ListCommandProcessor<ListCommand> {
    ...
    Listing<MyList,ListCommand> listing =
    new Listing<MyList,ListCommand> ();
    listing.setProcessor(this);

    public void onListCommand(ListCommand cmd)
    {
    switch (cmd) {
    ...
    }
    }
    }


    An alternative approach might be to remove ListCommandProcessor
    altogether and use a more OO approach by implementing functionality
    inside the ListCommand (what is an enum now but could be something else).

    Library part:

    public interface ListCommand<T> {
    void execute(T list);
    }

    public class Listing<T> {
    ...
    public void someMethod() {
    final T list = ...
    final ListCommand<T> cmd = ...
    cmd.execute(list);
    }
    ...
    }



    Specific implementation:

    public class MyList {
    }

    // this could be anything, not just an enum
    public enum MyListCommand implements ListCommandProcessor<MyList> {
    OPEN {
    @Override
    public void onListCommand(MyList cmd) {
    // whatever
    }
    },
    EDIT {
    @Override
    public void onListCommand(MyList cmd) {
    // whatever
    }
    }
    ...
    }

    Kind regards

    robert
     
    Robert Klemme, Jun 15, 2014
    #8
  9. Laura Schmidt

    Roedy Green Guest

    On Sun, 15 Jun 2014 01:24:47 +0200, Laura Schmidt <>
    wrote, quoted or indirectly quoted someone who said :

    >How would you do this?


    The only tool I have found that might be remotely useful in this
    situation is having your enums implement an interface.
    --
    Roedy Green Canadian Mind Products http://mindprod.com
    Software gets slower faster than hardware gets faster.
    ~ Niklaus Wirth (born: 1934-02-15 age: 80) Wirth's Law
     
    Roedy Green, Jun 16, 2014
    #9
    1. Advertisements

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steve Franks
    Replies:
    2
    Views:
    1,553
    Steve Franks
    Jun 10, 2004
  2. Bruce Sam
    Replies:
    2
    Views:
    4,426
    Andrew McDonagh
    Jan 10, 2005
  3. Roedy Green

    extending enum

    Roedy Green, Jul 31, 2005, in forum: Java
    Replies:
    18
    Views:
    37,703
    chrismay
    Jun 25, 2011
  4. mrhicks
    Replies:
    2
    Views:
    713
    Dave Thompson
    Jun 10, 2004
  5. Simon Elliott

    extending enum's: what operators?

    Simon Elliott, Jan 9, 2006, in forum: C++
    Replies:
    7
    Views:
    726
    Pete Becker
    Jan 9, 2006
  6. Extending Enum

    , May 15, 2007, in forum: Java
    Replies:
    3
    Views:
    1,250
  7. Roedy Green

    Extending an enum

    Roedy Green, Jul 16, 2007, in forum: Java
    Replies:
    4
    Views:
    945
    Roedy Green
    Jul 16, 2007
  8. BlackHelicopter
    Replies:
    0
    Views:
    997
    BlackHelicopter
    Jan 31, 2013
Loading...