Go Back   RunUO - Ultima Online Emulation > Developer's Corner > Programming > C#

C# C# Discussion

Reply
 
Thread Tools Display Modes
Old 10-20-2006, 12:19 PM   #1 (permalink)
Forum Newbie
 
poorchava's Avatar
 
Join Date: May 2006
Location: Wroclaw, Poland
Age: 21
Posts: 63
Send a message via MSN to poorchava
Default switching with 2 variables

Can i use switch with more than one argument? I mean something like this:
Code:
switch(a,b)
{
case 1,5:P{some stuff}
case 1,6:P{some stuff}
case 1,7:P{some stuff}
case 2,5:P{some stuff}
case 3,5:P{some stuff}

}
poorchava is offline   Reply With Quote
Old 10-20-2006, 01:24 PM   #2 (permalink)
Forum Expert
 
Join Date: Feb 2005
Age: 24
Posts: 985
Send a message via AIM to Nochte
Default

no

<too short>
Nochte is offline   Reply With Quote
Old 10-25-2006, 11:55 AM   #3 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

You could, theoretically, concatenate your numbers together into a single string, and then case on the stringified permutations.

case "a,b": ...

Kind of ugly, possibly slow.

There are of course a fair number of other ways to do this, but nothing quite so compact and elegant as the thing you asked if you could do.

If you could do it (which you can't), it would be because C# would have a language native form called a "tuple". Languages that do have tuples allow this sort of thing, and more. Another example of something that you can do with tuple supporting languages is this:

a, b = myfunction();

Or also:

(a, b) += (1, 2);

And of course, the case you mentioned:

switch( a, b ) {
case( 1, 2) :
...

But alas, can't do any of these in C#. Would be nice if you could!

C//
Courageous is offline   Reply With Quote
Old 10-25-2006, 12:28 PM   #4 (permalink)
RunUO Forum Moderator
 
daat99's Avatar
 
Join Date: Dec 2004
Location: Israel
Age: 27
Posts: 8,163
Send a message via ICQ to daat99 Send a message via AIM to daat99
Default

Code:
if ( a==1)
{
   if (b==5)
      stuff
   else if (b==6)
      stuff
   else if (b==7)
      stuff
}
else if (b==5)
{
   if (a==2)
      stuff
   else if (a==3)
      stuff
}
That's the shortest way I know of doing what you want in c#.
If someone know of a better way than PLEASE let me know too.
__________________
I always try to help
Sometimes, I don't know how....

My Web Page
Forum Rules
-------------------------------------------------------------
Extensive OWLTR System | Token System | World Teleporters
-------------------------------------------------------------
daat99 is offline   Reply With Quote
Old 10-25-2006, 02:38 PM   #5 (permalink)
Newbie
 
Join Date: Nov 2004
Posts: 30
Default

You might try something like

switch(slct[a,b])
{
case "1_5":P{some stuff}
case "1_6":P{some stuff}
case "1_7":P{some stuff}
case "2_5":P{some stuff}
case "3_5":P{some stuff}
}

where you have set up the array slct to have the values required (also include a default if necessary)

You can increment or set your indexes and get a testable string from the array.
Vindekator is offline   Reply With Quote
Old 10-25-2006, 02:58 PM   #6 (permalink)
RunUO Forum Moderator
 
daat99's Avatar
 
Join Date: Dec 2004
Location: Israel
Age: 27
Posts: 8,163
Send a message via ICQ to daat99 Send a message via AIM to daat99
Default

Quote:
Originally Posted by Vindekator
You might try something like

switch(slct[a,b])
{
case "1_5":P{some stuff}
case "1_6":P{some stuff}
case "1_7":P{some stuff}
case "2_5":P{some stuff}
case "3_5":P{some stuff}
}

where you have set up the array slct to have the values required (also include a default if necessary)

You can increment or set your indexes and get a testable string from the array.
If you're going this way you may want to skip the array and just do:
Code:
switch (a+","+b)
{
   case "1,5": bla bla
   case "1,6": bla bla
   case "1,7": bla bla
   case "2,5": bla bla
   case "3,5": bla bla
}
Same effect but you don't need to declare and set values in a string array.
Keep in mind that working with strings (or string array) use a lot of cpu power and is definatly not advised.
__________________
I always try to help
Sometimes, I don't know how....

My Web Page
Forum Rules
-------------------------------------------------------------
Extensive OWLTR System | Token System | World Teleporters
-------------------------------------------------------------
daat99 is offline   Reply With Quote
Old 10-26-2006, 04:29 AM   #7 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

I wouldnt want to go over any code you guys have written

Speed is really irrevelant in such a case and you cant really say shorter code is the fastest one.

I would write it as clear as possible and in a more logical way.

this is clear but it is not logical
Code:
if ( a==1)
{
   if (b==5)
      stuff
   else if (b==6)
      stuff
   else if (b==7)
      stuff
}
else if (b==5)
{
   if (a==2)
      stuff
   else if (a==3)
      stuff
}
just use:
Code:
if (a==1)
//bla bla
else
//..
or
Code:
if (a==xx && b==zz)
else if ..
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 10-26-2006, 10:55 AM   #8 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

Code:
if (a==xx && b==zz)
else if ..
I think the above is the clearest and most legible. Your prior remark about having just one check for a with all the b checks embedded was correct as well. Generally the beginner should start with that form before chaining logical ands together (as you show above), on the grounds that the results can be a bit confounding in more complicated cases.

C//
Courageous is offline   Reply With Quote
Old 10-28-2006, 03:58 PM   #9 (permalink)
xir
Forum Newbie
 
Join Date: Jul 2004
Posts: 59
Default

I beleive switches are generally faster than chained if statements, especially if you have loads of them. To my knowledge switches are placed into a lookup table with an offset. After the comparison is done the program counter is set to the piece of code.

P.S. Found a reference
http://en.wikipedia.org/wiki/Jump_table
xir is offline   Reply With Quote
Old 10-28-2006, 06:47 PM   #10 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

It may or may not be that switches are sometimes unrolled to loop tables. However, until one knows the performance concerns of a section of code, one should write code principally for other humans, and not the computer. Agreeably, switch is often pretty clear.

C//
Courageous is offline   Reply With Quote
Old 10-28-2006, 07:19 PM   #11 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

I really doubt using switch with string concat would much faster than regular a few if-else statements. btw it also has to build that look up table.

anyway event it were faster, does it really matter? how faster could it make it in such a simple case?? nanoseconds??
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 10-28-2006, 08:51 PM   #12 (permalink)
RunUO Forum Moderator
 
daat99's Avatar
 
Join Date: Dec 2004
Location: Israel
Age: 27
Posts: 8,163
Send a message via ICQ to daat99 Send a message via AIM to daat99
Default

Quote:
Originally Posted by noobie
I really doubt using switch with string concat would much faster than regular a few if-else statements. btw it also has to build that look up table.

anyway event it were faster, does it really matter? how faster could it make it in such a simple case?? nanoseconds??
On the countrary, using a string will be a lot slower than if/else.
When you do a lot of string operations you really use a lot more cpu than you may think, you should really avoid string operations where possible.
__________________
I always try to help
Sometimes, I don't know how....

My Web Page
Forum Rules
-------------------------------------------------------------
Extensive OWLTR System | Token System | World Teleporters
-------------------------------------------------------------
daat99 is offline   Reply With Quote
Old 10-28-2006, 11:53 PM   #13 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

Contatenating the strings is relatively expensive.

Checking for ==/!= is one instruction, even for strings, because C# strings are internalized. An internalized string is essentially a pointer to a string in a table, such that, at any given time, two strings that are spelled the same are actually the same object. If they have the same address, they are the same string, and if they don't, they aren't. So C# just compares their (internal) memory addresses. One instruction for that, basically. Very fast.

Hacking the strings together prolly isn't a good idea. Some set of ifs is the right way to do this.

C//
Courageous is offline   Reply With Quote
Old 10-29-2006, 02:48 AM   #14 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

Actually, as far as I know strings in .NEt has an exception for that. It overloads == operator and calls Object.Equal() method for comparisons. So it shouldnt compare the references but objects itself.

Anyway what I meant was actually crappy code vs speed. If you are doing a large amount of iterations, you could change it if it gets faster but otherwise it is not worth it since it compeletely loses its readibility..
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 10-29-2006, 10:25 AM   #15 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

The default implementation of Equal for strings is a reference comparison. C# internalizes strings for exactly this performance related reason. The following test confirms this, as there is only a minor difference between the two performance tests, where, if string matching were being performed, the two tests would very greatly in times (they do not).

Code:
using System;
using System.Collections;
using System.Collections.Generic;
//------------------------------------------------------------------------------
public class Test
{
    private static int[,]  m_Integers = new int[,]
    {
        {  1,  3 },
        {  3,  3 },
        {  3,  5 },
        {  5,  5 },
        {  5,  7 },
        {  7,  7 },
        {  7, 11 },
        { 11, 11 },
        { 11, 13 },
        { 13, 13 },
    };
    private static string[,]  m_Strings = new string[,]
    {
        { "thisisaridculouslylongstring_one",      "thisisaridculouslylongstring_three" },
        { "thisisaridculouslylongstring_three",    "thisisaridculouslylongstring_three" },
        { "thisisaridculouslylongstring_three",    "thisisaridculouslylongstring_five" },
        { "thisisaridculouslylongstring_five",     "thisisaridculouslylongstring_five" },
        { "thisisaridculouslylongstring_five",     "thisisaridculouslylongstring_seven" },
        { "thisisaridculouslylongstring_seven",    "thisisaridculouslylongstring_seven" },
        { "thisisaridculouslylongstring_seven",    "thisisaridculouslylongstring_eleven" },
        { "thisisaridculouslylongstring_eleven",   "thisisaridculouslylongstring_eleven" },
        { "thisisaridculouslylongstring_eleven",   "thisisaridculouslylongstring_thirteen" },
        { "thisisaridculouslylongstring_thirteen", "thisisaridculouslylongstring_thirteen" },
    };
//------------------------------------------------------------------------------
    
    public static void Main( string[] args )
    {
        {
            double  start = DateTime.Now.Ticks / 10000000.0;

            long count = 0;
            for( long i=0; i<100000000; i++)
            {
                int index = (int)( i % 10L );

                if( m_Integers[index,0]==m_Integers[index,1] ) count++;
            }
            double  stop = DateTime.Now.Ticks / 10000000.0;
            double  elapsed = stop - start;

            Console.WriteLine("INTEGERS");
            Console.WriteLine("    count: "+count);
            Console.WriteLine("    elapsed: "+elapsed);
        }
        {
            double  start = DateTime.Now.Ticks / 10000000.0;

            long count = 0;
            for( long i=0; i<100000000; i++)
            {
                int index = (int)( i % 10L );

                if( m_Strings[index,0]==m_Strings[index,1] ) count++;
            }
            double  stop = DateTime.Now.Ticks / 10000000.0;
            double  elapsed = stop - start;

            Console.WriteLine("STRINGS");
            Console.WriteLine("    count: "+count);
            Console.WriteLine("    elapsed: "+elapsed);
        }
    }
}
//------------------------------------------------------------------------------
On my computer, I (correctly) calculate 50,000,000 matches for each case, but case one takes 3.70 seconds, and case two takes 4.65. The difference in times is probably associated with the function dispatch, but then recouped by the reference (pointer address) compare. I should imagine that if Int were used instead of the primitive int, these tests would come out the same.

C//

Last edited by Courageous; 10-29-2006 at 10:28 AM.
Courageous is offline   Reply With Quote
Old 10-29-2006, 03:41 PM   #16 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

C, I dont get the point with your code..

I dont have any compiler right now but try these ones:

string a="mystr";
string b="mystr";

Console.WriteLine(a==b); //true
Console.WriteLine(a.Equals(b)); //true


however then try this one:

int x=5;

Console.WriteLine((Object)x == (Object)x); //false
Console.WriteLine(x.Equals(x)); //true


and finally try this one:
Object x=5;
Object y=5;

Console.WriteLine(x==y); //false
Console.WriteLine(x.Equals(y)); //true


So string camparisons with == operator is different than others.

(I couldnt test it.Let me know if any results is not same with mine)
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 10-29-2006, 03:47 PM   #17 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

C, I dont get the point with your code...

If it were having to compare every letter of the string, it would have to be many times slower, but it's not. The difference between 100,000,000 compares in the two sets of code is only 1 second. It does address compares (under the hood), with some added overhead. QED.

C//

Last edited by Courageous; 10-29-2006 at 03:53 PM.
Courageous is offline   Reply With Quote
Old 10-29-2006, 04:23 PM   #18 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

Small difference doesnt mean it uses references to compare.And why should it mean something like that?? integer comparisons dont use reference comparisons..

This is just a guess, I'll look into it but I think for integer comparisons, it box the value and then calls Int32.Equals() method. Thats why the difference is not huge. Another reason could be caching and optimization done by CLR since none of those variables hasnt change.


Anyway, if you compare my first and third examples, I think it is very clear..
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 10-29-2006, 04:32 PM   #19 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

Quote:
Small difference doesnt mean it uses references to compare. And why should it mean something like that?

See quote below.


Quote:
integer comparisons dont use reference comparisons..
Integers don't need to. They are a unique number. You can use a single assembler instruction to compare them per se. Strings don't have that property on any modern silicon I know of. So they are "internalized" in such a fashion that any two strings that are spelled the same (are "lexigraphically identical" is the technical term) have the same address in memory. You can then know that if the address is the same, they are the same string, and if not, not.

C# internalizes strings and does reference comparison for equality check by default. Why? Because it's the only fast way to do this. It's also memory-compact, which is why any virtual machine worth its salt always uses string internalization.

But by all means, don't believe me. Here's a direct quote from MSDN:



Quote:
The common language runtime conserves string storage by maintaining a table, called the intern pool, that contains a single reference to each unique literal string declared or created programmatically in your program. Consequently, an instance of a literal string with a particular value only exists once in the system. For example, if you assign the same literal string to several variables, the runtime retrieves the same reference to the literal string from the intern pool and assigns it to each variable.
I suppose, thinking about it, it would be possible to assign a unique number to a master object, and compare that number itself. Same/same. And kind of pointless. The address of any object in the table is a unique number itself.





C//

Last edited by Courageous; 10-29-2006 at 04:38 PM.
Courageous is offline   Reply With Quote
Old 10-29-2006, 04:50 PM   #20 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

What you are saying basicly is "str"=="str" returns false..

Normally, Equals method compare the objects by value and == operator compares them by reference

I am pretty sure it doesnt use references to compare. As I said before, string class overloads == operator and calls Equals() method. Easiest way would be just checking IL code of String class by a disassembler but I dont have even .net framework right now
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 10-29-2006, 05:24 PM   #21 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

Quote:
What you are saying basicly is "str"=="str" returns false...
Sheeesh. I am not. What I am saying is that two different strings, each spelled "str", are in fact actually the same string. That's what the MSDN docs are saying, too. FYI.

C//

Last edited by Courageous; 10-29-2006 at 05:34 PM.
Courageous is offline   Reply With Quote
Old 10-30-2006, 03:07 AM   #22 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

Possibly not what actually happens in the production .NET runtime, but according to Rotor, String.op_Equality calls String.Equals(String, String) which then first does a reference comparison, then if the reference compare comes back false, it does a value comparison. According to Reflector (which I assume disassembles the installed .NET dlls) this behavior also exists in the String class which is in the installed dlls.

The MSDN documentation for String.op_Equality also agrees with this
Quote:
Remarks:

This operator is implemented using the Equals method, which means the comparands are tested for a combination of reference and value equality. This operator performs an ordinal comparison.
Also, (as far as I know) strings are not interned automatically (unless you're talking about string constants which are present in the metadata, of course) instead they must be entered into the table via the String.Intern method and retrieved via the same method.

Then, there's also another remark in the documentation for String.Intern
Quote:
Performance Considerations:

If you are trying to reduce the total amount of memory your application allocates, keep in mind that interning a string has two unwanted side effects. First, the memory allocated for interned String objects is not likely be released until the common languange runtime (CLR) terminates. The reason is that the CLR's reference to the interned String object can persist after your application, or even your application domain, terminates. Second, to intern a string, you must first create the string. The memory used by the String object must still be allocated, even though the memory will eventually be garbage collected.
Which also leads to the conclusion that strings are not interned by default, even internally, but instead are interned on-demand.


Of course, in all of this I would like to point out, partially for myself, that when it comes to anything past the runtime itself (such as the actual code that the JIT produces and any optimizations it does with the actual machine code generated) all bets are off and anything is possible.

Last edited by Sep102; 10-30-2006 at 03:10 AM.
Sep102 is offline   Reply With Quote
Old 10-30-2006, 10:13 AM   #23 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

I reran the test by filling the table with string.Copy()'s of the strings instead of the constants, and indeed the string rand about twice as long as the integer test (I would have expected it to be even longer, given the length of the strings, so something is funny there).

I then manually interned this non constant string, and the test dropped back to the original performance figures.

So you would appear to be correct. Only constant strings are interned in the .net runtime. When they are, they are reference compared.

C//

Last edited by Courageous; 10-30-2006 at 01:23 PM.
Courageous is offline   Reply With Quote
Old 10-30-2006, 01:09 PM   #24 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

so, it uses both reference and value comparison. I didnt know .NEt has an option like internalization of strings. it could be useful where lots of string operation needed.
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 10-30-2006, 10:53 PM   #25 (permalink)
Forum Expert
 
Courageous's Avatar
 
Join Date: Nov 2005
Location: San Diego, CA
Posts: 1,824
Default

Generally speaking, internalization is quite good. The docs seem to be hinting that the internalization tables aren't garbage collected. A shame.

That's an inadequacy of the CLR, I say. Hopefully they fix it.

C//
Courageous is offline