Valhalla Legends Archive

Programming => General Programming => Java Programming => Topic started by: Joe[x86] on November 12, 2005, 06:00 PM

Title: Switching through strings?
Post by: Joe[x86] on November 12, 2005, 06:00 PM
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?
Title: Re: Switching through strings?
Post by: dxoigmn on November 12, 2005, 07:14 PM
if-else statements? hash the string to get an integer representation and switch on that?
Title: Re: Switching through strings?
Post by: Joe[x86] on November 12, 2005, 07:33 PM
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.
Title: Re: Switching through strings?
Post by: MyndFyre on November 14, 2005, 01:55 AM
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.
Title: Re: Switching through strings?
Post by: 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 :(
Title: Re: Switching through strings?
Post by: Joe[x86] 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.
Title: Re: Switching through strings?
Post by: dxoigmn on November 14, 2005, 11:35 AM
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.
Title: Re: Switching through strings?
Post by: 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). 
Title: Re: Switching through strings?
Post by: rabbit on November 14, 2005, 06:49 PM
String.hashCode() (http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#hashCode()) works just fine for switch statements.
Title: Re: Switching through strings?
Post by: dxoigmn on November 14, 2005, 08:34 PM
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).
Title: Re: Switching through strings?
Post by: iago on November 16, 2005, 09:13 PM
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. 
Title: Re: Switching through strings?
Post by: Ender on November 18, 2005, 06:54 PM

if (Object1.equals(Object2)) {
          System.out.println("Make Joe dance");
}



Title: Re: Switching through strings?
Post by: Ender on December 21, 2005, 02:53 PM
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