2013-01-25

C# Blooper №12: 'Where' constraints not included in method signatures


Before reading any further, please read the disclaimer.

When writing generic methods in C#, it is possible to use the 'where' keyword to specify constraints to the types that the generic parameters can take. Unfortunately, these constraints cannot be used for resolving overloaded methods. Case in point:

namespace Test12
{
    class Test
    {
        public static bool Equals<T>( T a, T b ) where T: class
        {
            return object.Equals( a, b );
        }

        public static bool Equals<T>( T a, T b ) where T: struct //error CS0111: Type 'Test' already defines a member called 'Equals' with the same parameter types
        {
            return a.Equals( b );
        }
    }
}

-

2013-01-14

C# Blooper №11: Zero to Enum conversion weirdness


Before reading any further, please read the disclaimer.

When you assign an enum to int, you have to cast it. That's good. When you assign an int to enum, you also have to cast it. That's also good. But if you assign zero to an enum, you don't have to cast it! Go figure.

namespace Test11
{
    class Test
    {
        public enum myenum
        {
            a, b, c
        }

        void test_myenum( myenum f, int i )
        {
            i = (int)myenum.a; //need to cast; that's good.
            f = (myenum)5; //need to cast; that's still good.
            f = 0; //wtf? no need to cast?
        }
    }
}

-

2013-01-08

C# Blooper №10: Switch statements are not properly formatted.


Before reading any further, please read the disclaimer.

This is rather a Microsoft Visual Studio blooper than a Microsoft C# blooper: When formatting source code, Visual Studio offers an "indent case contents" option, but you will only find it useful if you happen to have a crooked notion as to how switch statements should be formatted. The one and only normal form of formatting switch statements is not supported.

namespace Test10
{
    class Test
    {
        void statement() { }

        void test( int a )
        {
            /* with "indent case contents" option selected: */
            switch( a )
            {
                case 42:
                    /* this is not properly indented */
                    {
                        statement();
                        break;
                    }
                default:
                    /* this is properly indented */
                    statement();
                    break;
            }

            /* with "indent case contents" option deselected: */
            switch( a )
            {
                case 42:
                /* this is properly indented */
                {
                    statement();
                    break;
                }
                default:
                /* this is not properly indented */
                statement();
                break;
            }

            /* the normal way of indenting cannot be achieved: */
            switch( a )
            {
                case 42:
                {
                    statement();
                    break;
                }
                default:
                    statement();
                    break;
            }
        }
    }
}

I know, you might disagree that my way of formatting switch statements is in any way 'normal'. So, in your case, let us agree on this: my way of formatting switch statements, whether you like it or not, is in perfect accordance to the way I format the rest of my code; and since Visual Studio allows me to precisely describe my coding style, it should also allow for a switch statement style that matches the rest of my code.

-

2013-01-07

C# Blooper №9: Annoying case statement fall-through rules.


Before reading any further, please read the disclaimer.

Overall, C# takes an approach which is far more friendly to novice programmers than its predecessors, C and C++ were. For example, in the case of switch statements, C# does not allow the old, error-prone style of C and C++ where you could simply fall through from one case statement to the following one; instead, at the end of each case statement C# requires either a break statement, or a goto statement to explicitly jump to another label. That's all very nice and dandy, except for one thing: C# requires a break or goto even at the last case statement of a switch statement!

namespace Test9
{
    class Test
    {
        void statement() { }

        void wtf_is_it_with_falling_through_the_last_case_label( int a )
        {
            switch( a )
            {
                case 42:
                    statement();
                    break;
                default:
                    statement();
                    break; //Need this 'break' or else: CS0163: Control cannot fall through from one case label ('default:') to another
            }
        }
    }
}

I mean, seriously, WTF?

-

2013-01-04

C# Blooper №8: No warnings for conditions that are always true/false


Before reading any further, please read the disclaimer.

The Microsoft C# compiler does not issue 'condition is always true' and 'condition is always false' warnings. Perhaps these warnings are not particularly meaningful in Java, which lacks conditional compilation directives, and therefore if( true ) and if( false ) are the only means of achieving conditional compilation; but in C#, which has special conditional compilation directives, conditions which are always true or always false are invariably so by mistake; therefore, these warnings would indeed be meaningful, and useful.

namespace Test8
{
    class Test
    {
        void statement() { }

        void test()
        {
            if( true ) //no warning about 'condition is always true'.
                statement();

            while( false ) //no warning about 'condition is always false', even though the compiler obviously knows what's going on, since the following warning is issued:
                statement(); //warning CS0162: Unreachable code detected 
        }
    } 
}


For more information see Why the Microsoft C# compiler lacks many useful warnings.

-

C# Blooper №7: No warnings about unused private methods.


Before reading any further, please read the disclaimer.

If you have a private method which is never used, you will not be given a warning about it by the Microsoft C# compiler. This means that your app will likely get shipped with unnecessary chunks of code in it, some of them possibly containing string litterals that were never meant to make it out of the development environment, or even requiring libraries to be linked which were never meant to be required on the field.

namespace Test7
{
    class Test
    {
        private void unused() //no warning about unused private method.
        {
        }
    }
}

For more information see Why the Microsoft C# compiler lacks many useful warnings.

-

2012-11-29

C# Blooper №6: No warnings about unused parameters.


Before reading any further, please read the disclaimer.

One common mistake that programmers make is to forget to make use of a parameter to a method. This can lead to quite subtle bugs that are hard to track down and correct.

Now, other language compilers are kind enough to warn the programmer that a parameter is unused, and they also allow temporary suppression of the warning for the rare case when such lack of use is legitimate. But not so in Visual C#. If you forget to use a parameter in Visual C#, you will not know unless you run the "Code Analysis" tool on it.

namespace Test6
{
    class Test
    {
        void moo( int a ) //no warning about unused parameter 'a'.
        {
        }
    }
}


For more information see Why the Microsoft C# compiler lacks many useful warnings.

-

2012-11-13

Why the Microsoft C# compiler lacks many useful warnings

As my C# Bloopers series of articles shows, the Microsoft C# compiler fails to issue many useful warnings which one would reasonably expect from a decent compiler of any language, and which are in fact readily and lavishly issued by Java compilers.

After all these years that the Microsoft C# compiler has been maturing, one cannot help but postulate that there are alterior motives behind this continued state of misery with respect to warnings. For lo and behold, it just so happens that the "Ultimate" (most feature-packed and most outrageously expensive) edition of Microsoft Visual Studio contains a "Code Analysis" feature, which is capable of issuing hundreds of different types of warnings, ranging from the pedantic to the arcane, and including most, if not all, of the missing warnings that I am discussing here.

Now, besides the fact that the Code Analysis feature comes at a considerable additional cost, it is also very cumbersome to use on a frequent basis, since it has been built as a separate product feature, instead of having been integrated into the compiler. For one thing, it is very slow. Another thing is that it is very spammy: we are talking about multiple warnings for every single line of code here, most of which are useless, and the first thing you need to do about them is to turn them off. And there are several dozen warnings to turn off. 

This cumbersomeness makes the Code Analysis feature unsuitable for use in the instant builds which developers tend to perform every few minutes or so, and more suitable to use as a separate code-quality-assurance step to be performed once or twice during the entire development process of a product, or at best on nightly builds. Unfortunately, it is precisely on instant builds that the warnings I am talking about in these articles are most useful. Better yet, most of these warnings are useful in real-time, while typing the code, in the form of yellow curly underlines. For example, as a developer, I want to know that a parameter to a method I have just written goes unused before I even proceed to start coding the next method, because it most probably means that I forgot something or I did something wrong. This information is useful not tomorrow, not in a couple of months, but right now.

So, what has probably happened here is that the Microsoft C# compiler team was told by Microsoft's marketing department to intentionally cripple the C# compiler and make it less useful to all of us, by moving some of the functionality which rightfully belongs to it into some other module, so that their premium "Ultimate" product can have a raison d'être.

I bet you that Balmer is behind this.

2012-11-12

C# Blooper №5: Lame/annoying variable scoping rules, Part 2


Before reading any further, please read the disclaimer.

In light of the previous blooper, this one is more of a confusing error message than an actual new blooper. What I am doing below is that I am declaring a field within a class, I am accessing that field from within a method, and further down within the same method I am declaring a new local variable with the same name as the field. Now, C# will not allow me to declare that local variable because it has the same name as the field, but that's not where I am receiving the error. Instead, the error is given when accessing the field. If you only read the first sentence of the error message, it does not make any sense at all. If you bother also reading the second sentence, it gives you a hint as to the real problem. Now, that's not very cool.

namespace Test5
    {
        public class Test
        {
            public int a;

            void foo()
            {
                for( int i = 0;  i < 10;  i++ )
                {
                    a = 10; //error CS0844: Cannot use local variable 'a' before it is declared. The declaration of the local variable hides the field 'Test5.Test.a'.
                }
                string a = "";
                Console.WriteLine( a );
            }
        }
    }

See also: C# Blooper №4: Lame/annoying variable scoping rules, Part 1
-

2012-11-09

How to get a raise

Once upon a time I was dissatisfied with my salary at my workplace, and I let it show. The boss, fearing that he was about to lose me, placed an ad in the newspaper for my exact job description. Since I was looking for a job, I saw the ad in the newspaper. What I did was to reply to that ad, sending my boss my resume, which of course included precisely those qualifications that the job required. The boss got the message.