Java Forum / General / November 2007
Case expression must be constant expression
Philipp - 22 Nov 2007 12:39 GMT Hello, I don't understand why the following code gives a compilation error. In the "case" statements, the compiler complains that "Case expression must be constant expression", but as far as I can see, the expression are constant.
Thanks for any comments Phil
--- SSCCE ---
public class SwitchTest { public final int a = 1; public final int b = 2; public final int c = 3;
public SwitchTest() {}
public static void main(String[] args) { SwitchTest object = new SwitchTest();
int choice = 2;
switch(choice){ case object.a: System.out.println("a"); break; case object.b: System.out.println("b"); break; case object.c: System.out.println("c"); break; default: System.out.println("other"); } } }
Stefan Ram - 22 Nov 2007 12:45 GMT >but as far as I can see, the expression are constant. As far as I can see, the expression are not on the list as given in:
»15.28 Constant Expression«
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.28
Patricia Shanahan - 22 Nov 2007 14:52 GMT >> but as far as I can see, the expression are constant. > [quoted text clipped - 4 lines] > > http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.28 But would be on the list if the fields a, b, and c were static as well as final.
Non-static fields, even if declared final, can have different values for different instances of the class.
Patricia
chinmoy.titan@gmail.com - 22 Nov 2007 14:59 GMT > >> but as far as I can see, the expression are constant. > [quoted text clipped - 12 lines] > > Patricia Hi if u see u are giving object.a, but object is an instance variable...its just stores the address. Similarly if u keep a string in a switch case...it will give u a compilation error...because switch doesnot allow instance variables...in ur code u declared c as int and gave a value as 2 which is a primitive datatype..but in "case" u are refering to an instance..so it wont take ur code...
Lew - 22 Nov 2007 15:08 GMT > if u see u are giving object.a, but object is an instance > variable...its just stores the address. Similarly if u keep a string > in a switch case...it will give u a compilation error...because switch > doesnot allow instance variables...in ur code u declared c as int and > gave a value as 2 which is a primitive datatype..but in "case" u are > refering to an instance..so it wont take ur code... Just a gentle suggestion - please take the care to use full words and spacing. Txtspeek is awful stuff and looks unbelievably illiterate. It also makes the message harder to read.
 Signature Lew
Ramon F Herrera - 25 Nov 2007 22:10 GMT > chinmoy.ti...@gmail.com wrote: > > if u see u are giving object.a, but object is an instance [quoted text clipped - 10 lines] > -- > Lew I agree with you, Lew. It seems that we have a whole generation of people who has learned how to type on cell phones and IMs!
-Ramon
bugbear - 22 Nov 2007 12:45 GMT > Hello, > I don't understand why the following code gives a compilation error. In [quoted text clipped - 11 lines] > public final int b = 2; > public final int c = 3; I believe (too lazy to check) that only "static final" is deemed a full blown constant by the language/compiler.
BugBear
Gordon Beaton - 22 Nov 2007 12:51 GMT > I don't understand why the following code gives a compilation error. > In the "case" statements, the compiler complains that "Case > expression must be constant expression", but as far as I can see, > the expression are constant. Well, "object" in your example is not a compile-time constant. If your lables had been static, then you could have specified them as "SwitchTest.a" etc.
See section 15.28 in the JLS for the relevant definition: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.28
/gordon
--
Roedy Green - 23 Nov 2007 08:34 GMT >"Case expression must >be constant expression", but as far as I can see, the expression are >constant. By "constant", they don't mean final. they mean "known at compile time". They mean literals or compile time constants.
See http://mindprod.com/jgloss/literal.html http://mindprod.com/jgloss/constant.html
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Philipp - 23 Nov 2007 09:37 GMT >> "Case expression must >> be constant expression", but as far as I can see, the expression are [quoted text clipped - 5 lines] > See http://mindprod.com/jgloss/literal.html > http://mindprod.com/jgloss/constant.html Hello On your very clear and understandable page http://mindprod.com/jgloss/constant.html (which IMHO is not the case of the JLS), you write:
4. Instance Constants: <snip> It is sometimes possible for an instance constant to be evaluated at compile time. In that case it is treated like a literal, much like a static compile-time constant.
Isn't this exactly the case of my example in the original post? Isn't it an instance constant which can be evaluated at compile time?
Btw, I wanted to use a switch in my code, but due to these limitation it's now a if/else stack...
Best regards Phil
Lew - 23 Nov 2007 09:40 GMT > On your very clear and understandable page > http://mindprod.com/jgloss/constant.html (which IMHO is not the case of > the JLS), you write: The purpose of the JLS is not expository, it's to be precise and unambiguous. In particular, it specifies how a Java compiler must behave.
It is useful when one wants to know exactly what's what in the language, less so for learning the concepts until you get used to it. Then it's priceless.
 Signature Lew
Roedy Green - 23 Nov 2007 10:59 GMT >The purpose of the JLS is not expository, it's to be precise and unambiguous. > In particular, it specifies how a Java compiler must behave. If it is too obscure, it fails in doing that. If it were peppered with a sufficient examples to illustrate each point, it would be much less ambiguous and more accessible. English is much less precise than a carefully chosen example set. The problem is even reasonably competent people can read the JLS and differ on what it means, or feel unsure they know what it means.
You want examples guaranteed to give a certain result or guaranteed to give an error message.
This has been a bugbear of mine since university days. I have often accused profs of making the simple sound complicated in order to impress rather than inform. Did you ever read the Algol 68 report? It is a classic case.
Another would be legal agreements that companies get their customers to sign. They are deliberately written so that customers have no idea what they are agreeing to. Look how many people bought "fire insurance" and discovered it did not compensate them in the California fires.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Joshua Cranmer - 23 Nov 2007 16:10 GMT >> The purpose of the JLS is not expository, it's to be precise and unambiguous. >> In particular, it specifies how a Java compiler must behave. [quoted text clipped - 5 lines] > competent people can read the JLS and differ on what it means, or feel > unsure they know what it means. Occasionally, one can get a better idea by reading the VM spec; the details of protected access, IMO, is an example where the VM spec is clearer than the JLS.
Still, the JLS could use with some more examples; it gives some examples where none are needed and leaves out some where one or more is needed.
 Signature Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
Roedy Green - 24 Nov 2007 08:30 GMT On Fri, 23 Nov 2007 10:59:17 GMT, Roedy Green <see_website@mindprod.com.invalid> wrote, quoted or indirectly quoted someone who said :
>This has been a bugbear of mine since university days. I have often >accused profs of making the simple sound complicated in order to >impress rather than inform. Did you ever read the Algol 68 report? It >is a classic case. We studied proof after proof in mathematics, but we never saw how one was actually constructed. It was like studying building construction without ever seeing anything but a completed building. Mathematicians were embarrassed about the way intuition and refinement went into a polished elegant, minimalist proof. They wanted to hide every trace the scaffolding had ever existed.
Similarly when we were studying group and ring theory, the profs would smack us down if we ever tried to think about concrete examples worked. This would contaminate your thinking they asserted. You would make unwarranted assumptions that applied only to special cases. They wanted you to argue and think purely from the abstract. I could see insisting your final proof was purely abstract, but I could not see why it was so wicked to use concrete examples to give your mind something concrete to think about.
As a kid I used to sell "cheat sheets" to fellow students for 5 cents each to give them rules of thumb, and intuitive hooks to help them solve math, physics, chemistry and genetics problems. Human problem solving is a sloppier trial-and-error business than we pretend.
One beauty of the Internet is anyone is free to compose instructional materials with any degree of informality they please.
My contention is humans are superb at generalising from a well-chosen set of examples. This is much easier than absorbing abstract rules. This is what you would expect since experience teaches by example. This is how all animals learn. Very rarely do you get presented with an abstract theory. Consider how much easier arithmetic is for a calculator than for a human. We humans are relatively inept even at applying the relatively simple rules of arithmetic.
Yet a human can solve a difficult problem like who would make a suitable roommate, one that can be thought of as reasoning from many examples.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Owen Jacobson - 23 Nov 2007 10:08 GMT > >> "Case expression must > >> be constant expression", but as far as I can see, the expression are [quoted text clipped - 17 lines] > Isn't this exactly the case of my example in the original post? Isn't it > an instance constant which can be evaluated at compile time? The specific example you showed, repeated here for clarity:
public final int a = 1;
... switch (someInt) { case object.a: ...
does not meet the definition of the phrase "constant expression" as defined in the JLS, even though in theory you could determine statically that a is always going to be 1 at that point in the code. The JLS doesn't demand that level of sophistication from the compiler: 'object' is not a constant expression, therefore no expression containing it can be a constant expression.[0]
Unless there's some wild deviation between your example and your real problem, I don't see why you can't make 'a' static final and refer to it as SwitchTest.a or some similar form. What're you working on? Maybe someone has a better suggestion than an if ladder.
[0] It's probably worth mentioning here that the ONLY reference type allowed in a constant expression is String. No other class can have constant values according to the JLS. Since String is the only class that can be instantiated without a 'new', this makes some sense.
Lew - 23 Nov 2007 10:15 GMT > Since String is the only class that can be instantiated without a 'new' int [] nums = { 1, 3, 5, 7 };
 Signature Lew
Owen Jacobson - 23 Nov 2007 17:21 GMT > > Since String is the only class that can be instantiated without a 'new' > > int [] nums = { 1, 3, 5, 7 }; Drat! Thanks Lew.
Ok, so Strings are special in other ways: array literals cause new objects to be constructed every time the expression is evaluated at runtime and String literals do not. :)
-Owen
Lew - 23 Nov 2007 17:36 GMT >>> Since String is the only class that can be instantiated without a 'new' >> int [] nums = { 1, 3, 5, 7 }; [quoted text clipped - 4 lines] > objects to be constructed every time the expression is evaluated at > runtime and String literals do not. :) The array instantiation example is completely irrelevant to the point you were making, that Strings can be compile-time constants, but I couldn't resist tweaking you a little there.
 Signature Lew
Philipp - 24 Nov 2007 13:19 GMT > What're you working on? > Maybe someone has a better suggestion than an if ladder. Yes, actually I was trying to make a replacement for an Enum in JRE 1.3 when I stumbled accross this "Constant in case expression" problem.
What I made to mimic an enum is a class with static final members of itself inside (see example code below). But in this case I can't use the ordinal in a switch statement...
Phil
--SSCE-- (notice the missing C :-)
import java.util.HashMap;
public class Month{ private final int ordinal; private static final HashMap correspondanceMap = new HashMap();
private Month(int ordinal) { this.ordinal = ordinal; correspondanceMap.put(new Integer(ordinal), this); }
public static final Month JANUARY = new Month(1); public static final Month FEBRUARY = new Month(2); public static final Month MARCH = new Month(3); public static final Month APRIL = new Month(4);
public int getOrdinal(){ return ordinal; }
public static Month byOrdinal(int ordinal){ return (Month)correspondanceMap.get(new Integer(ordinal)); }
public int hashCode() { return ordinal; }
public boolean equals(Object h_type){ if (!(h_type instanceof Month)) return false; if ( ((Month)h_type).getOrdinal() == getOrdinal()) return true; else return false; }
public static void main(String[] args) { System.out.println("April's ordinal is: " + Month.APRIL.getOrdinal());
Month m = Month.byOrdinal(2); if(m.equals(Month.FEBRUARY)){ System.out.println("Both are equal."); }
// switch doesn't work int choice = 3; switch(choice){ case Month.JANUARY.getOrdinal(): System.out.println("Do something for January"); case Month.FEBRUARY.getOrdinal(): System.out.println("Do something for February"); case Month.MARCH.getOrdinal(): System.out.println("Do something for March"); case Month.APRIL.getOrdinal(): System.out.println("Do something for April"); default: System.out.println("None of those months"); } } }
Lew - 24 Nov 2007 13:20 GMT > Yes, actually I was trying to make a replacement for an Enum in JRE 1.3 > when I stumbled accross this "Constant in case expression" problem. Check out the "type-safe enum", as explained by Joshua Bloch in /Effective Java/, for example.
 Signature Lew
Roedy Green - 23 Nov 2007 12:04 GMT >Isn't this exactly the case of my example in the original post? Isn't it > an instance constant which can be evaluated at compile time? nope.
SwitchTest object = new SwitchTest();
int choice = 2;
switch(choice){ case object.a:
The address of object is not known until the program runs. The object.a does not exist at compile time.
had you written:
public static final int a = 1; public static final int b = 2; public static final int c = 3; ... switch(choice){ case a: or case SwitchTest.a:
then the value would be known at compile time.
Had you left out the static, I don't know what would happen. The compiler might say NO on the grounds it does not know the value of any fields in an object at compile time. The compiler might say OK, on the grounds, it can deduce the values, even at compile time.
From a practical point of view, there is no point in leaving out the static when the value is known at compile time. The only point in an instance constant is when the value differs for each instance of the object, or its value cannot be determined until the object is instantiated.
Java literature does not make as clean a distinction between the seven flavours of constant as I would like.
It is presented as a vague soup. You figure it out on your own by discovering what the compiler will eat.
If you follow these rules of thumb, you will get by without having to fully understand constants:
Avoid literals other than 0 and 1. Use static finals instead.
If a value can be known at compile or load time, mark it static final. If a value does not change after you compute it, mark it final. This applies to static variables, instance variables, local variables and parameters.
If in doubt whether a value is ok for a case, try it. If the compiler does not complain, it was ok.
If your constants need to be computed in some special order, put that initialisation in a static {} or an instance intialisation {} block where the order won't be meddled with. Don't trust the order of declarations. Some tidying program such as IntelliJ Idea Rearranger will eventually disturb the variable declaration order leaving you or someone else baffled why the initialisation no longer works.
If you change the value of a static final, do a clean recompile of all places it is used to propagate the new value.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Lew - 23 Nov 2007 16:35 GMT > Java literature does not make as clean a distinction between the seven > flavours of constant as I would like. There are seven?
 Signature Lew
Roedy Green - 24 Nov 2007 08:32 GMT >> Java literature does not make as clean a distinction between the seven >> flavours of constant as I would like. > >There are seven? see http://mindprod.com/jgloss/constant.html
for the seven types. There categories are mine, nothing official in Java.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Patricia Shanahan - 23 Nov 2007 14:31 GMT >>> "Case expression must be constant expression", but as far as I can >>> see, the expression are constant. [quoted text clipped - 9 lines] > http://mindprod.com/jgloss/constant.html (which IMHO is not the case of > the JLS), you write: The JLS is the authoritative description of the language, and as such has to be extremely precise. It is often very difficult, if not impossible, to explain things both precisely and simply.
> 4. Instance Constants: <snip> > It is sometimes possible for an instance constant to be evaluated at [quoted text clipped - 3 lines] > Isn't this exactly the case of my example in the original post? Isn't it > an instance constant which can be evaluated at compile time? I think the quote may relate to optimizations that the compiler can choose to do without changing the language. Your code would require a change in the Java language, away from what the JLS specifies.
> Btw, I wanted to use a switch in my code, but due to these limitation > it's now a if/else stack... I don't understand why you did that. Your original code would have worked fine if you had added "static" to each of the declarations:
public static final int a = 1; public static final int b = 2; public static final int c = 3;
Given the "final" and the constant initializer, I don't see any benefit to having a separate copy of each variable for each object of your class, rather than a single copy shared by all objects.
There is a subset of switch situations that every compiler can implement faster or more compactly than their if-then-else equivalent. The Java designers choose to limit the switch syntax to those situations.
However, I would have preferred it if they had allowed unrestricted switch, allowing any expressions and any type, using == comparison for primitives and equals() method for references.
At the worst, the compiler would generate a sequential if-then-else stack, the same code as you converted to. The other implementations would be optimizations relative to that code.
Patricia
Daniel Pitts - 23 Nov 2007 17:54 GMT >>> "Case expression must be constant expression", but as far as I can >>> see, the expression are constant. [quoted text clipped - 23 lines] > Best regards > Phil Just a note, have you considered using enums or even use a polymorphic object instead of switch?
<http://virtualinfinity.net/wordpress/program-design/2007/10/22/using-enums-as-a- flyweight-pattern/>
In Object Oriented design, its considered a likely problem if you have a switch statement (or a switch like construct). While there are *some* times when a switch is appropriate, I've found that I haven't used a switch statement once I understood the State, Strategy, and Flyweight patterns.
As an aside more direct to your original post, is there a good reason to make them *not* static final int?
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Ed Kirwan - 24 Nov 2007 09:56 GMT > In Object Oriented design, its considered a likely problem if you have a > switch statement (or a switch like construct). While there are *some* > times when a switch is appropriate, I've found that I haven't used a > switch statement once I understood the State, Strategy, and Flyweight > patterns. Hej, Daniel,
Would you say that a switch statement is inappropriate in a parameterised factory method, such as the one below?
http://www.edmundkirwan.com/servlet/fractal/cs1/code/package101.html#getEvaluation
And if inappropriate, how should parameterised factory methods look? Or would you say that parameterised factory methods are inherently un-OO?
I'm curious because I use them quite a lot and am wondering whether I should drop them in favour of something else.
 Signature .ed
www.EdmundKirwan.com - Home of encapsulation theory.
Daniel Pitts - 24 Nov 2007 18:30 GMT >> In Object Oriented design, its considered a likely problem if you have a >> switch statement (or a switch like construct). While there are *some* [quoted text clipped - 14 lines] > I'm curious because I use them quite a lot and am wondering whether I should > drop them in favour of something else. In your example, where does rank come from? Is it assigned specific values based on another if/else block?
This seems to me to fit my example of using an enum as a flyweight: <http://virtualinfinity.net/wordpress/program-design/2007/10/22/using-enums-as-a- flyweight-pattern/>
Basically, you have a Rank abstract class/interface which has the implementations HighestCard, OnePair, TwoPairs, etc....
The interface would have a HandEvaluation getEvaluation(Hand hand); Your factory method could remain. It would simply delegate to rank.getEvaluation(hand);
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
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 ...
|
|
|