Java Forum / General / September 2007
Using an enum in a constructor
Wojtek - 20 Sep 2007 21:33 GMT Given the following: --------------------------------- public class Foo { private static final int DEFAULT_LENGTH = 30; private Type ivType; private int ivLength;
public enum Type { OTHER, FIXED, VARIABLE; }
public Foo(Type type) { this(type,DEFAULT_LENGTH); }
public Foo(Type.VARIABLE varType, int length) { this(varType,length); }
private Foo(Type type, int length) { super(); ivType = type; ivLength = length; } } ---------------------------------
The compiler complains that Type.VARIABLE cannot be used. Obviously what I want is that if the Type is VARIABLE, then I want the length in the constructor, otherwise I will use the default length.
And yes I know I can have a constructor that only takes (int length) and then assume that the Type is VARIABLE. That is not the point here.
 Signature Wojtek :-)
Gary Coulbourne - 20 Sep 2007 22:13 GMT > The compiler complains that Type.VARIABLE cannot be used. Obviously what > I want is that if the Type is VARIABLE, then I want the length in the > constructor, otherwise I will use the default length. I don't believe you can do what you're asking in Java as it stands. All of the elements of your enum are of type Type. So Type VARIABLE isn't special in any way that would allow the constructor to differentiate. You could, perhaps, make a function that took variable arguments, and if the first argument was of type VARIABLE, only then look to the second argument. But, then you'd lose compile-time type safety.
Peace, Gary
 Signature -------------------------------------------------------------------- Gary Coulbourne Software Developer C/C++, Java, Perl, Python
Wojtek - 20 Sep 2007 22:40 GMT Gary Coulbourne wrote :
>> The compiler complains that Type.VARIABLE cannot be used. Obviously what >> I want is that if the Type is VARIABLE, then I want the length in the >> constructor, otherwise I will use the default length. > > I don't believe you can do what you're asking in Java as it stands. That is what I thought. It would be nice to be able to enforce this through type safety though.
> All > of the elements of your enum are of type Type. So Type VARIABLE isn't > special in any way that would allow the constructor to differentiate. Well yes, except that all the enum elements are there. The way I see it, the enum is the type, but the enum elements are a enum "sub-type", statically created the first time the class is used. The run-time should be able to differentiate between them.
 Signature Wojtek :-)
Lasse Reichstein Nielsen - 21 Sep 2007 00:20 GMT > Well yes, except that all the enum elements are there. The way I see > it, the enum is the type, but the enum elements are a enum "sub-type", No, they are values, not types (even though there might be a separate anonymous class hidden in the implementation). An enumerated type has a fixed number of values.
What you might want is a constructor:
public Foo(int length) { this(Type.VARIABLE, length); }
or if you that's too obscure (it probably is), use a factory method with a telling name:
public static Foo createVariabelFoo(int length) { return new Foo(Type.VARIABLE, length); }
/L
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Daniel Pitts - 20 Sep 2007 22:16 GMT > Given the following: > --------------------------------- [quoted text clipped - 39 lines] > -- > Wojtek :-) Try using the Static Factory approach instead
public class Foo { enum Type { a, b, c }
private Foo(Type type, int length) { // ... }
public static Foo createVariable(int length) { return new Foo(Type.a, length); }
public static Foo createSomething(Type type) { return new Foo(type, DEFAULT_LENGTH; } public sattic Foo createSomething(Type type, int length) { return new Foo(type, length); } }
Wojtek - 20 Sep 2007 22:34 GMT Daniel Pitts wrote :
>> Given the following: >> --------------------------------- [quoted text clipped - 62 lines] > } > } This is the same as having a constructor which takes just (int length). I still need to make an assumption that type is VARIABLE.
 Signature Wojtek :-)
Daniel Pitts - 20 Sep 2007 22:59 GMT > Daniel Pitts wrote : > [quoted text clipped - 70 lines] > -- > Wojtek :-) Its not an assumption, its explicit by the name of the method "createVariable"!
In general though, if you have a "Type" token, you might be going about your solution the wrong way. Have you considered using a more polymorphic approach?
abstract class Foo { }
class VariableFoo extends Foo { }
class OtherFoo extends Foo { }
etc...
That way, the "Type" of foo, is actually the *type* of foo! (Go figure).
Or, if the Type can change over time, use the State pattern (same idea, just wrapper)
class Foo { FooType type;
public Foo(FooType type) {} }
abstract class FooType { }
class FooVariable extends FooType { FooVariable(int length) {} }
class FooOther extends FooType { }
Wojtek - 20 Sep 2007 23:29 GMT Daniel Pitts wrote :
>> This is the same as having a constructor which takes just (int length). >> I still need to make an assumption that type is VARIABLE. >> > Its not an assumption, its explicit by the name of the method > "createVariable"! Sorry, did not read it through :-(
> In general though, if you have a "Type" token, you might be going > about your solution the wrong way. Have you considered using a more [quoted text clipped - 10 lines] > > etc... Yes, it could be done that way. I am refactoring the class and its use anyways, so 6 == dozen/2, though your six has benefits.
I am converting:
public static final int VARIABLE = 0x01; public static final int OTHER = 0x02;
etc, and converting to an enum seemed a natural approach
I only have 800+ places to refactor...
 Signature Wojtek :-)
Daniel Pitts - 21 Sep 2007 00:09 GMT > Daniel Pitts wrote : > [quoted text clipped - 35 lines] > -- > Wojtek :-)
:-) Moving from "int" style type-codes to "enum" style is a step in the right direction. Replacing types-codes/switches with polymorphism is the real goal of an OO designer.
I suggest reading a good refactoring book. I've read both "Refactoring" by Martin Fowler, and "Refactoring to Patterns" by Joshua Kerievsky. I would recommend either one (Kerievsky frequently references Fowler).
Roedy Green - 21 Sep 2007 00:28 GMT >public class Foo >{ [quoted text clipped - 8 lines] > VARIABLE; > } You have this as a nested inner instance class. I have always made my enums separate top level classes. Perhaps you are allowed to define them as static inner classes. Perhaps there are magic exceptions made for enums to the usual nesting rules. Is there a language lawyer about?
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Joshua Cranmer - 21 Sep 2007 00:38 GMT >> public class Foo >> { [quoted text clipped - 14 lines] > for enums to the usual nesting rules. Is there a language lawyer > about? JLS §8.9 (I think; I haven't checked since Wednesday) says that all enums are implicitly static classes and not inner instance classes. Therefore:
public class Foo { public enum Type { } }
and
public class Foo { public static enum Type { } }
are equivalent.
 Signature Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
Wojtek - 21 Sep 2007 00:38 GMT Roedy Green wrote :
>> public class Foo >> { [quoted text clipped - 14 lines] > for enums to the usual nesting rules. Is there a language lawyer > about? We have had this discussion before, but I do not remember seeing your example.
If I use the above, then I reference it with Foo.Type.FIXED.
What does your separate top level enum class look like, and how do you reference it?
 Signature Wojtek :-)
Daniel Pitts - 21 Sep 2007 16:20 GMT > Roedy Green wrote : > [quoted text clipped - 27 lines] > -- > Wojtek :-) /* MySeperateEnum.java */ public enum MySeperateEnum { A,B,C; }
/*SomeOtherClass.java*/ public class SomeOtherClass { MySeperateEnum value = MySeperateEnum.A;
}
Wojtek - 23 Sep 2007 19:21 GMT Daniel Pitts wrote :
>> Roedy Green wrote : >> [quoted text clipped - 38 lines] > > } Ah, ok, I see now. This enum beast is kind of a funny sort of class....
So I can create a separate class for the enum (as per your example), or nest it in the class where it is used (as per my example).
So if it is being used elsewhere in the system I need two import statements vs one.
I kind of prefer the nesting approach, as the location (and reference) indicates the enums logical ownership.
 Signature Wojtek :-)
Daniel Pitts - 23 Sep 2007 20:00 GMT Sorry if this gets double posted. GG is on the fritz again!
> Daniel Pitts wrote : > [quoted text clipped - 42 lines] > > Ah, ok, I see now. This enum beast is kind of a funny sort of class.... Actually, it is in more ways than you might suspect.
enum MyEnum { A { public void doSomething() { System.out.println("Something on A"); } }, B{ public void doSomething() { System.out.println("B does something"); } }, C{ public void doSomething() { System.out.println("C you later!"); } };
public abstract void doSomething(); }
MyEnum is an abstract base class of MyEnum.A (and .B, etc..). You can add methods, fields (good practice to make those final), and even constructors to the enum and members. You can even add members to the specifics (MyEnum.A) that aren't in the parent (MyEnum).
I've used this idiom to implement the flyweight pattern in conjunction with the strategy/state pattern. Although, I usually find that eventually I need even more flexibility (better polymorphic structure), and end up refactoring away from the enum approach. Not to say enums aren't a good interim step, or prototype step before that approach.
> So I can create a separate class for the enum (as per your example), or > nest it in the class where it is used (as per my example). > > So if it is being used elsewhere in the system I need two import > statements vs one. I don't count imports as statements personally. I think of them more as directives. You can always give the fully qualified class name in place of using the imports.
> I kind of prefer the nesting approach, as the location (and reference) > indicates the enums logical ownership. Indeed. If the enum has a logical owner, then it makes much sense to have that owner, ahem, own it!
On the other hand, if it doesn't have a *single* logical owner (which does happen on occasion), it should probably be its own separate entity.
Good luck, Daniel.
Roedy Green - 23 Sep 2007 23:09 GMT >Ah, ok, I see now. This enum beast is kind of a funny sort of class.... Enums made no sense until I started decompiling code and seeing how they work under the hood. I have posted the results of my experiments at http://mindprod.com/jgloss/enum.html
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Lew - 23 Sep 2007 23:27 GMT >> Ah, ok, I see now. This enum beast is kind of a funny sort of class.... > > Enums made no sense until I started decompiling code and seeing how > they work under the hood. I have posted the results of my experiments > at http://mindprod.com/jgloss/enum.html I love that article. It clarifies enum semantics for me.
I do have one small nit over it, with respect to specifics of nested class terminology:
> I have managed to get nested static inner enums and nested instance inner enums to work as well, There isn't actually a difference for enums:
> Nested enum types are implicitly static. > It is permissable to explicitly declare a nested enum type to be static. <http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9>
Also, an "inner class" according to the JLS is the opposite of static nested, which both are subcategories of nested classes:
> An /inner class/ is a nested class that is not explicitly or implicitly declared static. (emphasis original) <http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3>
The terms as defined by the JLS are much more specific than they are in general usage.
 Signature Lew
Roedy Green - 24 Sep 2007 00:03 GMT >The terms as defined by the JLS are much more specific than they are in >general usage. I got in the habit of calling them "inner classes" and "static inner classes" before someone explained the proper terminology. I went over the http://mindprod.com/jgloss/enum.html entry tightening the wording.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Joshua Cranmer - 23 Sep 2007 23:45 GMT >> Ah, ok, I see now. This enum beast is kind of a funny sort of class.... > > Enums made no sense until I started decompiling code and seeing how > they work under the hood. I have posted the results of my experiments > at http://mindprod.com/jgloss/enum.html In answer to your question: I wondered wonder why Sun didn't just use the enum ordinals directly as case numbers.
My current understanding is that it is to promote binary compatibility: changing the order of the enum constants wouldn't break the switch statement under this scheme. Sun really does go far to try and keep code binary-compatible. (I believe Andrew Thompson was the one who pointed this out sometime over the summer)
 Signature Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
Roedy Green - 24 Sep 2007 00:53 GMT On Sun, 23 Sep 2007 22:45:31 GMT, Joshua Cranmer <Pidgeot18@verizon.net> wrote, quoted or indirectly quoted someone who said :
>My current understanding is that it is to promote binary compatibility: >changing the order of the enum constants wouldn't break the switch >statement under this scheme. Sun really does go far to try and keep code >binary-compatible. Thanks. I have updated the entry http://mindprod.com/jgloss/enum.html
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
smcardle@smcardle.com - 21 Sep 2007 13:09 GMT > Given the following: > --------------------------------- [quoted text clipped - 39 lines] > -- > Wojtek :-) So what about this then
public class Foo { private static final int DEFAULT_LENGTH = 30; private Type ivType; private int ivLength;
public enum Type { OTHER, FIXED, VARIABLE; }
public Foo(Type type) { this(type,DEFAULT_LENGTH); }
public Foo(Type type, int length) { ivType = type; switch(type) { case VARIABLE: ivLength = DEFAULT_LENGTH; break; default: ivLength = length;
} } }
Steve
Lew - 21 Sep 2007 13:38 GMT > switch(type) { > case VARIABLE: [quoted text clipped - 4 lines] > > } Nine times out of ten, a switch() like this is a red flag that polymorphism should be used instead.
 Signature Lew
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|