This is annoying. Very annoying. You're only allowed to switch ints. =(.
So, anyhow, I'm working on commands in TAHCBot. Say, you want to switch through the first word (defined by splitting at spaces), for things like "say", "quit", etc. How would you handle this?
if-else statements? hash the string to get an integer representation and switch on that?
Quote from: dxoigmn on November 12, 2005, 07:14 PM
if-else statements?
Doing that right now.
Quote from: dxoigmn on November 12, 2005, 07:14 PM
hash the string to get an integer representation and switch on that?
Hm, thats not all that bad of an idea.
You're only allowed to switch on constants. So technically you'd be allowed to switch true/false also. :P Did I mention that C# supports string constants as native for switch? (Not that it's a great idea anyway).
One other thing you might consider before choosing the hashing option: compilers look for ways to optimize things. For example, suppose you had the following switch block:
switch (value)
{
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
}
I don't know if javac does this, but the C# compiler will. It uses divide-and-conquer to optimize jumps. Where the emitted assembly might look like this without the optimization:
begin_switch:
cmp eax, 1
jz case_1
cmp eax, 2
jz case_2
cmp eax, 3
jz case_3
cmp eax, 4
jz case_4
cmp eax, 5
jz case_5
cmp eax, 6
jz case_6
cmp eax, 7
jz case_7
cmp eax, 8
jz case_8
cmp eax, 9
jz case_9
case_0: ; not referenced but for clarity.
goto end_switch
case_1:
goto end_switch
case_2:
goto end_switch
case_3:
goto end_switch
case_4:
goto end_switch
case_5:
goto end_switch
case_6:
goto end_switch
case_7:
goto end_switch
case_8:
goto end_switch
case_9:
end_switch:
Optimized code might look like this:
begin_switch:
cmp eax, 5
jge divide_and_conquer
cmp eax, 1
jz case_1
cmp eax, 2
jz case_2
cmp eax, 3
jz case_3
cmp eax, 4
jz case_4
jmp case_0
divide_and_conquer:
cmp eax, 5
jz case_5
cmp eax, 6
jz case_6
cmp eax, 7
jz case_7
cmp eax, 8
jz case_8
cmp eax, 9
jz case_9
case_0:
goto end_switch
case_1:
goto end_switch
case_2:
goto end_switch
case_3:
goto end_switch
case_4:
goto end_switch
case_5:
goto end_switch
case_6:
goto end_switch
case_7:
goto end_switch
case_8:
goto end_switch
case_9:
end_switch:
For any cases greater than 5 you half to do many less comparisons.
If you do that with hash values, you might be foregoing any way to do that with numbers that could be meaningful to you.
Does C# allow fall through? Seems like that optimization won't work when you have fall through.
Unfortunately, java only allows you to switch on integral types. So no true/false switching :(
You could probably typecast a boolean to a 0/1 integer rather easily. In fact, I know you could, writing your own function, but there's probably something in the API too.
Quote from: Joe on November 14, 2005, 07:06 AM
You could probably typecast a boolean to a 0/1 integer rather easily. In fact, I know you could, writing your own function, but there's probably something in the API too.
Yes but then each case-statement must contain a constant expression. So you're only going to be able to compare to 0 or 1. Not very useful.
Quote from: dxoigmn on November 14, 2005, 04:35 AM
Does C# allow fall through? Seems like that optimization won't work when you have fall through.
Unfortunately, java only allows you to switch on integral types. So no true/false switching :(
No, C# doesn't allow fall-through unless the case is empty:
switch (expr)
{
case 0:
case 1:
blah();
break;
case 2:
blah2();
break;
}
Does Java?
It really does only allow on integral types? I thought on any constant expression. (I guess using boolean types is silly, since it could be expressed as if/else, and floating-point would also be potentially bad because they're not precise).
String.hashCode() (http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#hashCode()) works just fine for switch statements.
Quote from: MyndFyre on November 14, 2005, 01:13 PM
Quote from: dxoigmn on November 14, 2005, 04:35 AM
Does C# allow fall through? Seems like that optimization won't work when you have fall through.
Unfortunately, java only allows you to switch on integral types. So no true/false switching :(
No, C# doesn't allow fall-through unless the case is empty:
switch (expr)
{
case 0:
case 1:
blah();
break;
case 2:
blah2();
break;
}
Does Java?
It really does only allow on integral types? I thought on any constant expression. (I guess using boolean types is silly, since it could be expressed as if/else, and floating-point would also be potentially bad because they're not precise).
Yes java does allow fall through, and yep only integral types. Another thing about your optimization, why would it not be faster to have a lookup table, O(1) vs O(lg(n)) :P? Is it due to MSIL? I suspect the reason java only allows integral types is to always take advantage of the lookup table optimization. Switching on boolean types would be nice, example:
switch(true) {
case myString.equals("foo"):
break;
case myString.equals("bar"):
break;
}
But even if switching on booleans were possible, still need constant expressions for the cases (in java).
I don't know about Java or C#, but in C, it looks more like this:
switch(value)
......
Goes to:
int addresses = { address_of_1, address_of_2, address_of_3, address_of_4, .........};
........
jmp addresses[value];
So it's actually a single jump, based in the int value. The only comparisons are for values that are too big/too small, and any values that aren't in the table are set to default for their address.
You just plain shouldn't use a switch() for anything besides integers. For strings, just use normal comparisons. Using a hashcode is kind of a silly idea.. it's not going to save you any time overall, and it will end up more obscure than before.
if (Object1.equals(Object2)) {
System.out.println("Make Joe dance");
}
You can emulate the full functionality that you would have in switching Strings by switching Enums.
example:
public class CoolOrNot {
private enum People { ENDER, BILLGATES, JOE }
public static void main(String[] args) {
for (String arg : args) { // loop through args passed to program
switch (People.valueOf(arg.toUpperCase()) {
case ENDER:
System.out.println("decision reached: the coolest and sexiest person alive"); // okay, perhaps I don't have a good sense of humor...
break;
case BILLGATES:
System.out.println("decision reached: even a penguin is cooler than bill gates"); // i know, lame...
break;
case JOE:
System.out.println("decision reached: highly controversial.");
break;
default:
System.out.println(arg + " is not documented.");
break;
}
}
}
}
And then you pass String args to the program. Here's an example with command-line functions (IDE's should support this as well though).
javac CoolOrNot.java
java CoolOrNot joe
btw, j/k joe :P
----
EDITS:
I just tested it and two things were wrong:
1) "Enum" is not capitalized, it is "enum" instead.
2) enum's can't be local. Also, they're automatically final and static.
LATER EDITS:
3) made a default case b/c that's good habit, even if just for testing purposes.
4) made a for-each loop because for-each loops are sexy