Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #9078 > unrolled thread

Enum mixin?

Started by"A. W. Dunstan" <no@spam.thanks>
First post2011-10-21 17:19 -0400
Last post2011-10-22 18:10 -0700
Articles 7 — 5 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Enum mixin? "A. W. Dunstan" <no@spam.thanks> - 2011-10-21 17:19 -0400
    Re: Enum mixin? Robert Klemme <shortcutter@googlemail.com> - 2011-10-21 23:37 +0200
      Re: Enum mixin? markspace <-@.> - 2011-10-21 16:16 -0700
        Re: Enum mixin? Robert Klemme <shortcutter@googlemail.com> - 2011-10-23 11:44 +0200
          Re: Enum mixin? Lew <lewbloch@gmail.com> - 2011-10-23 08:45 -0700
      Re: Enum mixin? "A. W. Dunstan" <no@spam.thanks> - 2011-10-24 09:23 -0400
    Re: Enum mixin? Roedy Green <see_website@mindprod.com.invalid> - 2011-10-22 18:10 -0700

#9078 — Enum mixin?

From"A. W. Dunstan" <no@spam.thanks>
Date2011-10-21 17:19 -0400
SubjectEnum mixin?
Message-ID<WsudnUpWT_V6fDzTnZ2dnUVZ_vCdnZ2d@speakeasy.net>
I'm writing a GUI that's a wrapper around some Fortran code.  In one of the 
Fortran routines I pass in an integer that tells the Fortran code what kind 
of 'cloud model' to use (it's a big physics simulation).  For example:

value   meaning
-----   ---------
0       no clouds
1       cumulus
2       altostratus
18      cirrus

etc.  The Fortran is 3'rd party software so changing values & their meanings 
isn't an option.

I'd use a plain enum but the values passed in aren't continuous (as above - 
it skips from 2 up to 18), nor do they necessarily start at zero.  So I 
wrote my own enum where I could associate a name, a value and a description:

public enum CloudModel {
	None(0, "No clouds"),
	Cumulus(1, "Cumulus"),
	AltoStratus(2, "Altostratus"),
	Cirrus(18, "Cirrus");

	CloudModel(int value, String description)
	{
		m_value = value;
		m_desc = description;
	}

	public int getValue() { return m_value; }

	public String toString() { return "" + m_value + ": " + m_desc; }

	private int m_value;
	private String m_desc;
}


This works but I'm now up to six different enums (Cloud coverage, 
atmospheric model, haze, surface reflectance, etc), and they all look nearly 
the same.  Each one has identical getValue() and toString() methods, m_value 
and m_desc.  And the constructor varies only in it's name - the body of each 
constructor is the same.  Creating a new enum is easy - cut & paste, change 
the name of the constructor, type in the values and I'm done.

This works too, but code reuse by cut-and-paste worries me.  I'd like to 
extract the methods & member variables into a base class of some sort and 
extend that, providing the enumeration values in each derived enum.  BUT - I 
can't extend from an enum.  If I could put the common parts in a separate 
class and mix that in (as in Ruby) that'd be great, but Java isn't Ruby.

My code will be called from Matlab (which can access Java objects & methods 
directly) so I'd like to keep it as an enum.  And enums are easy to load 
into a JComboBox, which makes that part of the GUI code cleaner.

I'm ok with leaving it the way it is, but does anyone know of a better 
approach?  Preferably one that's not so complex that it's worse than my 
current state of affairs?


-- 
Al Dunstan, Software Engineer
OptiMetrics, Inc.
3115 Professional Drive
Ann Arbor, MI  48104-5131

"There are two ways of constructing a software design.  One way is to
make it so simple that there are obviously no deficiencies.  And the
other way is to make it so complicated that there are no obvious
deficiencies."
            - C. A. R. Hoare

[toc] | [next] | [standalone]


#9080

FromRobert Klemme <shortcutter@googlemail.com>
Date2011-10-21 23:37 +0200
Message-ID<9ge71qFkv0U1@mid.individual.net>
In reply to#9078
On 21.10.2011 23:19, A. W. Dunstan wrote:
> I'm writing a GUI that's a wrapper around some Fortran code.  In one of the
> Fortran routines I pass in an integer that tells the Fortran code what kind
> of 'cloud model' to use (it's a big physics simulation).  For example:
>
> value   meaning
> -----   ---------
> 0       no clouds
> 1       cumulus
> 2       altostratus
> 18      cirrus
>
> etc.  The Fortran is 3'rd party software so changing values&  their meanings
> isn't an option.
>
> I'd use a plain enum but the values passed in aren't continuous (as above -
> it skips from 2 up to 18), nor do they necessarily start at zero.  So I
> wrote my own enum where I could associate a name, a value and a description:
>
> public enum CloudModel {
> 	None(0, "No clouds"),
> 	Cumulus(1, "Cumulus"),
> 	AltoStratus(2, "Altostratus"),
> 	Cirrus(18, "Cirrus");
>
> 	CloudModel(int value, String description)
> 	{
> 		m_value = value;
> 		m_desc = description;
> 	}
>
> 	public int getValue() { return m_value; }
>
> 	public String toString() { return "" + m_value + ": " + m_desc; }
>
> 	private int m_value;
> 	private String m_desc;
> }
>
>
> This works but I'm now up to six different enums (Cloud coverage,
> atmospheric model, haze, surface reflectance, etc), and they all look nearly
> the same.  Each one has identical getValue() and toString() methods, m_value
> and m_desc.  And the constructor varies only in it's name - the body of each
> constructor is the same.  Creating a new enum is easy - cut&  paste, change
> the name of the constructor, type in the values and I'm done.
>
> This works too, but code reuse by cut-and-paste worries me.  I'd like to
> extract the methods&  member variables into a base class of some sort and
> extend that, providing the enumeration values in each derived enum.  BUT - I
> can't extend from an enum.  If I could put the common parts in a separate
> class and mix that in (as in Ruby) that'd be great, but Java isn't Ruby.
>
> My code will be called from Matlab (which can access Java objects&  methods
> directly) so I'd like to keep it as an enum.  And enums are easy to load
> into a JComboBox, which makes that part of the GUI code cleaner.
>
> I'm ok with leaving it the way it is, but does anyone know of a better
> approach?  Preferably one that's not so complex that it's worse than my
> current state of affairs?

I don't think it gets any better.  Even if you go away from enums and 
create an abstract base class etc. you'll have to do the typing for the 
values plus you need to take care of serialization etc. (only once in 
the base class though) and you still need to define a constructor - even 
if it's then only

private Foo(int value, String description) {
   super(value, description);
}

But I would probably choose different names instead of calling them all 
getValue().  After all, these are all different values or having a 
different meaning in different enums.  If you do that the common base 
class wouldn't help you much any more.  I think I'd stick with enums.

Some more remarks: I'd make fields final because that's what they should 
be for an enum.  Since you are not accessing m_desc from anywhere 
outside you could make your code more efficient by storing the value 
returned by toString() in a String member.  Since you have those enums 
in the GUI I assume that toString() is invoked fairly often but the same 
String will be created over and over again so you could as well store that.

Kind regards

	robert


-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

[toc] | [prev] | [next] | [standalone]


#9081

Frommarkspace <-@.>
Date2011-10-21 16:16 -0700
Message-ID<j7sufj$ekp$1@dont-email.me>
In reply to#9080
On 10/21/2011 2:37 PM, Robert Klemme wrote:

> On 21.10.2011 23:19, A. W. Dunstan wrote:
>> I'm ok with leaving it the way it is, but does anyone know of a better
>> approach? Preferably one that's not so complex that it's worse than my
>> current state of affairs?

> I don't think it gets any better. Even if you go away from enums and
> create an abstract base class etc. you'll have to do the typing for the
> values plus you need to take care of serialization etc.


I would have thought that an abstract base class would get you what you 
need.  Maybe I'm overlooking something.  The second class here seems to 
remove a lot of boilerplate, esp considering my IDE will write the 
constructor for me (since it's the only one available).


package quicktest;

import java.io.Serializable;

public abstract class AbstactEnum implements Serializable {

    private final int value;
    private final String name;

    public AbstactEnum(int value, String name) {
       this.value = value;
       this.name = name;
    }

    public String getName() {
       return name;
    }

    public int getValue() {
       return value;
    }
}

final class CloudModel extends AbstactEnum {

    /*
     * value   meaning
    -----   ---------
    0       no clouds
    1       cumulus
    2       altostratus
    18      cirrus */
    public static final CloudModel NONE = new CloudModel(0, "No Clouds");
    public static final CloudModel CUMULUS = new CloudModel(1, "Cumulus");
    public static final CloudModel ALTOSTRATUS = new CloudModel(2, 
"Altostratus");
    public static final CloudModel CIRRUS = new CloudModel(18, "Cirrus");

    public CloudModel(int value, String name) {
       super(value, name);
    }
}

[toc] | [prev] | [next] | [standalone]


#9110

FromRobert Klemme <shortcutter@googlemail.com>
Date2011-10-23 11:44 +0200
Message-ID<9gi5vlFftnU1@mid.individual.net>
In reply to#9081
On 22.10.2011 01:16, markspace wrote:
> On 10/21/2011 2:37 PM, Robert Klemme wrote:
>
>> On 21.10.2011 23:19, A. W. Dunstan wrote:
>>> I'm ok with leaving it the way it is, but does anyone know of a better
>>> approach? Preferably one that's not so complex that it's worse than my
>>> current state of affairs?
>
>> I don't think it gets any better. Even if you go away from enums and
>> create an abstract base class etc. you'll have to do the typing for the
>> values plus you need to take care of serialization etc.
>
> I would have thought that an abstract base class would get you what you
> need. Maybe I'm overlooking something. The second class here seems to
> remove a lot of boilerplate, esp considering my IDE will write the
> constructor for me (since it's the only one available).

Well, for Al's original code you would also benefit from some IDE 
boilerplate generation.  Plus, if you rename the int property according 
to sub class then you gain even less.

> package quicktest;
>
> import java.io.Serializable;
>
> public abstract class AbstactEnum implements Serializable {

For serialization to work like with enum (i.e. always only those 
instances in memory that you define in the class) you need to do 
considerably more.  That effectively will be a reimplementation of enum. 
  Plus, it can be tricky to get concurrency right etc.  And you have the 
drawback that you need to do it yourself.

 > ...
> final class CloudModel extends AbstactEnum {
 > ...
> }

I find that not really much less typing than the original code.  Plus, 
it's not an enum which means you lose the immediate information which 
for example IDE's provide when showing an icon for the type of language 
element.

Kind regards

	robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

[toc] | [prev] | [next] | [standalone]


#9119

FromLew <lewbloch@gmail.com>
Date2011-10-23 08:45 -0700
Message-ID<7052235.68.1319384739900.JavaMail.geo-discussion-forums@yqoo7>
In reply to#9110
Robert Klemme wrote:
> markspace wrote:
>> Robert Klemme wrote:
>>> A. W. Dunstan wrote:
>>>> I'm ok with leaving it the way it is, but does anyone know of a better
>>>> approach? Preferably one that's not so complex that it's worse than my
>>>> current state of affairs?

Your current state of affairs is not that bad.  The problem is your prejudice against copy-and-paste.  There is no technical solution for that; you just have to get over it.

>>> I don't think it gets any better. Even if you go away from enums and
>>> create an abstract base class etc. you'll have to do the typing for the
>>> values plus you need to take care of serialization etc.
>>
>> I would have thought that an abstract base class would get you what you
>> need. Maybe I'm overlooking something. The second class here seems to
>> remove a lot of boilerplate, esp considering my IDE will write the
>> constructor for me (since it's the only one available).
>
> Well, for Al's original code you would also benefit from some IDE 
> boilerplate generation.  Plus, if you rename the int property according 
> to sub class then you gain even less.

+1.  

I generally put a "human-friendly" string representation of an enum constant into it:

  FOO("foo"), 
  BIG_EFFORT("big effort"), 

The code to write a static 'fromString()' and override the 'toString()' is boilerplate.  I set all my IDEs to produce that boilerplate for me when I ask for a new enum.

>> package quicktest;
>>
>> import java.io.Serializable;
>>
>> public abstract class AbstactEnum implements Serializable {
> 
> For serialization to work like with enum (i.e. always only those 
> instances in memory that you define in the class) you need to do 
> considerably more.  That effectively will be a reimplementation of enum. 
>   Plus, it can be tricky to get concurrency right etc.  And you have the 
> drawback that you need to do it yourself.

Oh, the price of not studying /Effective Java/, by Joshua Bloch (2nd ed.) (EJ)!

'Serializable' is one of the most heavily abused Java features.  Besides the tremendous amount of work it takes to actually get it right, contrary to its apparent simplicity, you are creating a permanent public interface into the private elements of the class, as EJ points out.  You really lose flexibility to refactor the implementation if you commit to a serialization format.

>> ...
>> final class CloudModel extends AbstactEnum {
>> ...
>> }
> 
> I find that not really much less typing than the original code.  Plus, 
> it's not an enum which means you lose the immediate information which 
> for example IDE's provide when showing an icon for the type of language 
> element.

There are some major drawbacks to creating a type-safe enumeration pre-Java 5 style compared to enums.  I can conceive of rare use cases for it, though.

Using type-safe enumerations requires the programmer to be responsible for all those messy details, though, as you so aptly point out.

-- 
Lew

[toc] | [prev] | [next] | [standalone]


#9144

From"A. W. Dunstan" <no@spam.thanks>
Date2011-10-24 09:23 -0400
Message-ID<cbWdnc3ADLdt-zjTnZ2dnUVZ_v2dnZ2d@speakeasy.net>
In reply to#9080
Robert Klemme wrote:

> On 21.10.2011 23:19, A. W. Dunstan wrote:
>> I'm writing a GUI that's a wrapper around some Fortran code.  In one of
>> the Fortran routines I pass in an integer that tells the Fortran code
>> what kind
>> of 'cloud model' to use (it's a big physics simulation).  For example:
>>
>> value   meaning
>> -----   ---------
>> 0       no clouds
>> 1       cumulus
>> 2       altostratus
>> 18      cirrus
>>
>> etc.  The Fortran is 3'rd party software so changing values&  their
>> meanings isn't an option.
>>
>> I'd use a plain enum but the values passed in aren't continuous (as above
>> -
>> it skips from 2 up to 18), nor do they necessarily start at zero.  So I
>> wrote my own enum where I could associate a name, a value and a
>> description:
>>
>> public enum CloudModel {
>> None(0, "No clouds"),
>> Cumulus(1, "Cumulus"),
>> AltoStratus(2, "Altostratus"),
>> Cirrus(18, "Cirrus");
>>
>> CloudModel(int value, String description)
>> {
>> m_value = value;
>> m_desc = description;
>> }
>>
>> public int getValue() { return m_value; }
>>
>> public String toString() { return "" + m_value + ": " + m_desc; }
>>
>> private int m_value;
>> private String m_desc;
>> }
>>
>>
>> This works but I'm now up to six different enums (Cloud coverage,
>> atmospheric model, haze, surface reflectance, etc), and they all look
>> nearly
>> the same.  Each one has identical getValue() and toString() methods,
>> m_value
>> and m_desc.  And the constructor varies only in it's name - the body of
>> each
>> constructor is the same.  Creating a new enum is easy - cut&  paste,
>> change the name of the constructor, type in the values and I'm done.
>>
>> This works too, but code reuse by cut-and-paste worries me.  I'd like to
>> extract the methods&  member variables into a base class of some sort and
>> extend that, providing the enumeration values in each derived enum.  BUT
>> - I
>> can't extend from an enum.  If I could put the common parts in a separate
>> class and mix that in (as in Ruby) that'd be great, but Java isn't Ruby.
>>
>> My code will be called from Matlab (which can access Java objects& 
>> methods
>> directly) so I'd like to keep it as an enum.  And enums are easy to load
>> into a JComboBox, which makes that part of the GUI code cleaner.
>>
>> I'm ok with leaving it the way it is, but does anyone know of a better
>> approach?  Preferably one that's not so complex that it's worse than my
>> current state of affairs?
> 
> I don't think it gets any better.  Even if you go away from enums and
> create an abstract base class etc. you'll have to do the typing for the
> values plus you need to take care of serialization etc. (only once in
> the base class though) and you still need to define a constructor - even
> if it's then only
> 
> private Foo(int value, String description) {
>    super(value, description);
> }
> 
> But I would probably choose different names instead of calling them all
> getValue().  After all, these are all different values or having a
> different meaning in different enums.  If you do that the common base
> class wouldn't help you much any more.  I think I'd stick with enums.
> 
> Some more remarks: I'd make fields final because that's what they should
> be for an enum.  Since you are not accessing m_desc from anywhere
> outside you could make your code more efficient by storing the value
> returned by toString() in a String member.  Since you have those enums
> in the GUI I assume that toString() is invoked fairly often but the same
> String will be created over and over again so you could as well store
> that.
> 
> Kind regards
> 
> robert
> 
> 

Both good ideas.  Thanks!

-- 
Al Dunstan, Software Engineer
OptiMetrics, Inc.
3115 Professional Drive
Ann Arbor, MI  48104-5131

"There are two ways of constructing a software design.  One way is to
make it so simple that there are obviously no deficiencies.  And the
other way is to make it so complicated that there are no obvious
deficiencies."
            - C. A. R. Hoare

[toc] | [prev] | [next] | [standalone]


#9099

FromRoedy Green <see_website@mindprod.com.invalid>
Date2011-10-22 18:10 -0700
Message-ID<v9q6a79f4ps6m9ltno17e03m32hgdk315f@4ax.com>
In reply to#9078
On Fri, 21 Oct 2011 17:19:29 -0400, "A. W. Dunstan" <no@spam.thanks>
wrote, quoted or indirectly quoted someone who said :

>I'm ok with leaving it the way it is, but does anyone know of a better 
>approach?  Preferably one that's not so complex that it's worse than my 
>current state of affairs?
 
I have fretted over this too.  There was a thread a week or so ago
about dynamic enums -- creating something like enums without using the
enum keywoard.
-- 
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to 
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web