Valhalla Legends Forums Archive | Java Programming | Switching through strings?

AuthorMessageTime
JoeTheOdd
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?
November 13, 2005, 12:00 AM
kamakazie
if-else statements? hash the string to get an integer representation and switch on that?
November 13, 2005, 1:14 AM
JoeTheOdd
[quote author=dxoigmn link=topic=13222.msg133785#msg133785 date=1131844470]
if-else statements?[/quote]
Doing that right now.

[quote author=dxoigmn link=topic=13222.msg133785#msg133785 date=1131844470]
hash the string to get an integer representation and switch on that?
[/quote]
Hm, thats not all that bad of an idea.
November 13, 2005, 1:33 AM
Myndfyr
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:
[code]
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;
}
[/code]
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:

[code]
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:
[/code]

Optimized code might look like this:
[code]
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:
[/code]

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.
November 14, 2005, 7:55 AM
kamakazie
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 :(
November 14, 2005, 10:35 AM
JoeTheOdd
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.
November 14, 2005, 1:06 PM
kamakazie
[quote author=Joe link=topic=13222.msg133920#msg133920 date=1131973578]
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]

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.
November 14, 2005, 5:35 PM
Myndfyr
[quote author=dxoigmn link=topic=13222.msg133919#msg133919 date=1131964520]
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 :(
[/quote]

No, C# doesn't allow fall-through unless the case is empty:

[code]
switch (expr)
{
  case 0:
  case 1:
  blah();
  break;
  case 2:
  blah2();
  break;
}
[/code]

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). 
November 14, 2005, 7:13 PM
rabbit
String.hashCode() works just fine for switch statements.
November 15, 2005, 12:49 AM
kamakazie
[quote author=MyndFyre link=topic=13222.msg133939#msg133939 date=1131995604]
[quote author=dxoigmn link=topic=13222.msg133919#msg133919 date=1131964520]
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 :(
[/quote]

No, C# doesn't allow fall-through unless the case is empty:

[code]
switch (expr)
{
  case 0:
  case 1:
  blah();
  break;
  case 2:
  blah2();
  break;
}
[/code]

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). 
[/quote]

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:

[code]
switch(true) {
    case myString.equals("foo"):
        break;
    case myString.equals("bar"):
        break;
}
[/code]

But even if switching on booleans were possible, still need constant expressions for the cases (in java).
November 15, 2005, 2:34 AM
iago
I don't know about Java or C#, but in C, it looks more like this:

[code]switch(value)
......
[/code]
Goes to:
[code]
int addresses = { address_of_1, address_of_2, address_of_3, address_of_4, .........};
........
jmp addresses[value];
[/code]

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. 
November 17, 2005, 3:13 AM
Ender
[code]
if (Object1.equals(Object2)) {
          System.out.println("Make Joe dance");
}
[/code]


November 19, 2005, 12:54 AM
Ender
You can emulate the full functionality that you would have in switching Strings by switching Enums.

example:
[code]
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;
                    }
            }
    }
}
[/code]

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).
[code]
javac CoolOrNot.java
java CoolOrNot joe
[/code]

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
December 21, 2005, 8:53 PM

Search