• Welcome to Valhalla Legends Archive.
 

Switching through strings?

Started by Joe[x86], November 12, 2005, 06:00 PM

Previous topic - Next topic

Joe[x86]

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?
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

dxoigmn

if-else statements? hash the string to get an integer representation and switch on that?

Joe[x86]

#2
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.
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

MyndFyre

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.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

dxoigmn

#4
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 :(

Joe[x86]

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: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

dxoigmn

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.

MyndFyre

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). 
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

rabbit

Grif: Yeah, and the people in the red states are mad because the people in the blue states are mean to them and want them to pay money for roads and schools instead of cool things like NASCAR and shotguns.  Also, there's something about ketchup in there.

dxoigmn

#9
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).

iago

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. 
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Ender


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




Ender

#12
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