enum and switch

W

Wojtek

From the compiler complaints I guess this is not possible, yet....

----------------------------
public class MyClass
{
public enum Things
{
ONE,TWO
}

public boolean process(Things thing)
{
boolean success = false;

switch ( thing )
{
case Things.ONE:
success = doStuff(1);
break;

case Things.TWO:
success = doStuff(2);
break;
}

return success;
}
 
D

Daniel Dyer

From the compiler complaints I guess this is not possible, yet....

----------------------------
public class MyClass
{
public enum Things
{
ONE,TWO
}

public boolean process(Things thing)
{
boolean success = false;

switch ( thing )
{
case Things.ONE:
success = doStuff(1);
break;

case Things.TWO:
success = doStuff(2);
break;
}

return success;
}

You don't need to qualify the enum constants. In fact, you are only
allowed to use unqualified names. So it should be:

switch (thing)
{
case ONE:
// Do something.
case TWO:
// Do something else.
}

Dan.
 
W

Wojtek

Daniel Dyer wrote :
You don't need to qualify the enum constants. In fact, you are only allowed
to use unqualified names. So it should be:

switch (thing)
{
case ONE:
// Do something.
case TWO:
// Do something else.
}

Dan.

OK, but what if the enum is from another class? I must then qualify it.

BTW I ended up using an if/else if tree, though I would rather use a
switch/case.
 
D

Daniel Dyer

OK, but what if the enum is from another class? I must then qualify it.

BTW I ended up using an if/else if tree, though I would rather use a
switch/case.

Did you try it with the switch statement and the unqualified labels? The
compiler knows what class the enum constants are from because it knows the
type of the argument to the switch statement.

Dan.
 
W

Wojtek

Daniel Dyer wrote :
Did you try it with the switch statement and the unqualified labels? The
compiler knows what class the enum constants are from because it knows the
type of the argument to the switch statement.

It works.

I would not have thought of this.....

Thanks!
 
D

Daniel Pitts

Did you try it with the switch statement and the unqualified labels? The
compiler knows what class the enum constants are from because it knows the
type of the argument to the switch statement.

Dan.

Or, even better... Ever hear of Polymorphism?

// Look ma! No Switches!
public class MyClass {
public enum Things {
ONE {
public boolean doStuff(MyClass myClass) {
return myClass.doStuff(1);
}
},
TWO {
public boolean doStuff(MyClass myClass) {
return myClass.doStuff(2);
}
}
;
public abstract boolean doStuff(MyClass myClass);

}

public boolean process(Things thing) {
return thing.doStuff(this);
}

private boolean doStuff(int i) {
return false;
}
}
 
S

Steve W. Jackson

Did you try it with the switch statement and the unqualified labels? The
compiler knows what class the enum constants are from because it knows the
type of the argument to the switch statement.

It works.

I would not have thought of this.....

Thanks![/QUOTE]

A more careful examination of the compiler error would actually tell you
this. I learned it the hard way after adopting a practice in an ongoing
project of *always* qualifying our enum references. The compiler
squawked and I had to read it several times to fully grasp that it was
telling me I could not do so.

= Steve =
 
W

Wojtek

Daniel Dyer wrote :
The
compiler knows what class the enum constants are from because it knows the
type of the argument to the switch statement.

Argh, inconsistencies drive me nuts...

So the compiler knows about the enum constants from the switch, but If
I have:

if ( thing == ONE )

That fails because I have not qualified the enum constant.
 
W

Wojtek

Daniel Pitts wrote :
Or, even better... Ever hear of Polymorphism?

// Look ma! No Switches!
public class MyClass {
public enum Things {
ONE {
public boolean doStuff(MyClass myClass) {
return myClass.doStuff(1);
}
},
TWO {
public boolean doStuff(MyClass myClass) {
return myClass.doStuff(2);
}
}
;
public abstract boolean doStuff(MyClass myClass);

}

public boolean process(Things thing) {
return thing.doStuff(this);
}

private boolean doStuff(int i) {
return false;
}
}

Well, ok, except that there is more happening in each case than a
method call. And I need to take the time to sit down and actually READ
about Java 1.5+

Sigh, not enough hours in each day, and those damn deadlines.....
 
W

Wojtek

Steve W. Jackson wrote :
A more careful examination of the compiler error would actually tell you
this. I learned it the hard way after adopting a practice in an ongoing
project of *always* qualifying our enum references. The compiler
squawked and I had to read it several times to fully grasp that it was
telling me I could not do so.

You are right of course. It is just that I am so used to qualifying
things, and along comes this new "feature".

The last thing I would have expected is that the compiler would qualify
it for me AND cause an error if I did.

Fully qualifying the constant should have produced a warning about an
unnecessary cast. IMHO of course :)
 
D

Daniel Pitts

Daniel Pitts wrote :







Well, ok, except that there is more happening in each case than a
method call. And I need to take the time to sit down and actually READ
about Java 1.5+

Sigh, not enough hours in each day, and those damn deadlines.....

The point is to move the change in behavior out of the switch
statement and into the object you are switching on.

public enum Things {
ONE {
public boolean doStuff(MyClass myClass) {
// Do lots of stuff to myClass
//...
}
},
TWO {
public boolean doStuff(MyClass myClass) {
// Do lots of stuff other stuff to myClass
//...
}
}
;
public abstract boolean doStuff(MyClass myClass);
}

This is called the State/Strategy pattern. You'll find that well
designed OO programs tend NOT to have switch statements. Especially
switch statements which switch on the same object in more than one
location. Just put a method on the object, and override it for the
different cases.
 
J

John W. Kennedy

Wojtek said:
Daniel Dyer wrote :

Argh, inconsistencies drive me nuts...

So the compiler knows about the enum constants from the switch, but If I
have:

if ( thing == ONE )

That fails because I have not qualified the enum constant.

In every ""switch(Enum), each "case" /must/ be a value of Enum. An "if",
on the other hand, can be any expression that eventually boils down to a
boolean.
 
P

Patricia Shanahan

John said:
In every ""switch(Enum), each "case" /must/ be a value of Enum. An "if",
on the other hand, can be any expression that eventually boils down to a
boolean.

That still does not explain why qualification is prohibited. It would
appear to be harmless, and in some situations make code more orthogonal,
provided the types match.

Patricia
 
D

Daniel Pitts

That still does not explain why qualification is prohibited. It would
appear to be harmless, and in some situations make code more orthogonal,
provided the types match.

Patricia
I agree, but what about this case (no pun intended):

public void foo(Thing thing) {
Integer ONE = 1;
switch (thing) {
case ONE: // case branches are never expression.
// so no ambiguity
}
if (thing == ONE) { // Ambiguous.
}
}

I think it has more to do with the fact that there can't ever be
ambiguity for case branches.
 
A

Andreas Leitgeb

..., and those damn deadlines.....

So, you don't like the swooshing sound as they pass by ???


Daniel Pitts said:
This is called the State/Strategy pattern. You'll find that well
designed OO programs tend NOT to have switch statements. Especially
switch statements which switch on the same object in more than one
location.

I'd say it mostly depends on how tightly related the switch body
is to the current class/method it is placed in.

Tearing apart logical units of code into separate classes is
also a good recipe for preventing reliably any future attempt
to understand what the code is actually doing.

My suggestion is to have a enum's method return the specific
parameters that allow the switch-arms to be united.
Where this is considered unfeasible, stick to switch.

Don't put any logic into an enum, that is not mainly related
to that enum.
 
W

Wojtek

Daniel Pitts wrote :
The point is to move the change in behavior out of the switch
statement and into the object you are switching on.

public enum Things {
ONE {
public boolean doStuff(MyClass myClass) {
// Do lots of stuff to myClass
//...
}
},
TWO {
public boolean doStuff(MyClass myClass) {
// Do lots of stuff other stuff to myClass
//...
}
}
;
public abstract boolean doStuff(MyClass myClass);
}

This is called the State/Strategy pattern. You'll find that well
designed OO programs tend NOT to have switch statements. Especially
switch statements which switch on the same object in more than one
location. Just put a method on the object, and override it for the
different cases.

So you are telling me that the enum (which is in another class) must
know about the business logic being evaluated?

The enum I am using is in a class which holds filter criteria. An array
of these filters is passed into a file reader. The file reader reads in
a line, then for each filter in the array evaluates the line. If the
line meets the conditions then it is placed into a collection, to be
written out to a Web page.

The filter array is built up in the business logic class of a use case.
The filter criteria is created by the user via a servlet. There is a
method which iterates through the filters and builds up a human
readable display of the filter criteria. With I18N conversion. To be
displayed at the top of the page which displays the results.

So I have this enum in two switch statements in two different places.
Putting both sets of business logic in the enum seems very wrong to me.
Even with overriding of methods, I would still need to have both method
signatures in the enum. Which means that the enum would still need to
know about what it is being used for. Which breaks use case separation.

And if the enum is in a library, then the library would need to be
modified each time the enum is used in a new place.

After all, an enum is just a way of gathering state criteria in a
convenient package (type). This can then be used as a parameter which
allows the compiler to ensure type safety.

I do not know about other OO languages, but the Java enum definition
which allows methods to be attached to enum elements is completely new
to me.
 
W

Wojtek

Wojtek wrote :
I do not know about other OO languages, but the Java enum definition which
allows methods to be attached to enum elements is completely new to me.

Ok, I can see having characteristics in the enum element.

In fact I am going to put the language key and a method
getLanguageKey() as part of each element.

But I do not think that behaviour should be there.
 
J

John W. Kennedy

Wojtek said:
I do not know about other OO languages, but the Java enum definition
which allows methods to be attached to enum elements is completely new
to me.

It was a natural result of Java's everything-is-an-object philosophy.
 
A

andrewmcdonagh

Daniel Pitts wrote :






So you are telling me that the enum (which is in another class) must
know about the business logic being evaluated?

The enum I am using is in a class which holds filter criteria. An array
of these filters is passed into a file reader. The file reader reads in
a line, then for each filter in the array evaluates the line. If the
line meets the conditions then it is placed into a collection, to be
written out to a Web page.

The filter array is built up in the business logic class of a use case.
The filter criteria is created by the user via a servlet. There is a
method which iterates through the filters and builds up a human
readable display of the filter criteria. With I18N conversion. To be
displayed at the top of the page which displays the results.

So I have this enum in two switch statements in two different places.
Putting both sets of business logic in the enum seems very wrong to me.
Even with overriding of methods, I would still need to have both method
signatures in the enum. Which means that the enum would still need to
know about what it is being used for. Which breaks use case separation.

And if the enum is in a library, then the library would need to be
modified each time the enum is used in a new place.

After all, an enum is just a way of gathering state criteria in a
convenient package (type). This can then be used as a parameter which
allows the compiler to ensure type safety.

I do not know about other OO languages, but the Java enum definition
which allows methods to be attached to enum elements is completely new
to me.

By using the enum in this way and having code spread throughout your
app which checks which enum is being referenced to decide what to do,
it sounds like your design needs to be 'normalised' in an OO way...as
Daniel suggests, by moving the decision making logic to a polymorphic
call on a Normal class. I say normal class, because I think going
from what you describe, you don't need an enum - you need a normal set
of classes.

Don't worry that you want to do different things with different
parameters, for each 'enum', this is solvable in a polymorphic way
too. (its the Strategy Pattern as Daniel says).

Essentially, keep the phrase 'Tell, don't ask' in mind when designing
your app, and this OO approach will naturally fall out.

Tell your objects to decide what they want to do, dont ask them for
information and then make the decision....


Andrew
 
W

Wojtek

andrewmcdonagh wrote :
By using the enum in this way and having code spread throughout your
app which checks which enum is being referenced to decide what to do,
it sounds like your design needs to be 'normalised' in an OO way

I can see that, except that I have delibrately de-normalized between
use cases. The use cases are pretty well separated from each other.

I can delete a use case without affecting any other use case. Except of
course that that functionality has gone, which may mean that the user
can no longer maintain helper tables. But it will run OK.

Everything else is in a framework. Those classes cannot be removed as
they are used everywhere.

So if an enum is in the framework, then it should NOT know about any
business logic which uses it.

For instance (putting on fire-proof-coat) :)
----------------
public class Value
{
// these are column IDs which we store in the database
// - do NOT change them, only add new ones
// - they must be unique
private static int LOGIC_AND_ID = 0;
private static int LOGIC_OR_ID = 1;

// these are column IDs which we store in the database
// - do NOT change them, only add new ones

public static enum Logic
{
/**
* All values must return true
*/
AND(LOGIC_AND_ID),

/**
* Any value can be true
*/
OR(LOGIC_OR_ID);

private Logic( int databaseID )
{
ivDatabaseID = databaseID;
}

private int ivDatabaseID;

public int getDatabaseID()
{
return ivDatabaseID;
}

/**
* Returns the Logic for a given database id number<br><br>
* Used to find a Logic from a Web page field or database column
*/
public static Logic getLogic( int databaseID )
throws EnumNotFoundException
{
for (Logic logic : Logic.values())
if (logic.getDatabaseID() == databaseID)
return logic;

throw new EnumNotFoundException( Logic.class.getName() + "(id: " +
databaseID + ")" );
}
}

// .. other universal values, such a number of milli-seconds in a
// second, minute, hour, day, and so forth
}
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,269
Latest member
vinaykumar_nevatia23

Latest Threads

Top