March 2008 - Posts

Resharper Isn't Always Smart

I was writing some code today, essentially like this:

public class MyClass

{

    private int value;

    public MyClass(int value)

    {

        this.value = value;

    }

    public static bool operator==(MyClass left, MyClass right)

    {

        return left.value == right.value;

    }

 

    public static bool operator !=(MyClass left, MyClass right)

    {

        return !(left == right);

    }

}

    //...

    MyClass myClass1 = new MyClass(1);

    MyClass myClass2 = new MyClass(1);

    if((Object)myClass1 != (Object)myClass2) // "Type cast is reundant"

    {

        Console.WriteLine("not equal");

    }

    else

    {

        Console.WriteLine("equal");

    }

...where Resharper warned that both the casts to Object were redundant and offered a "Quick-fix" (red light bulb) to "Remove cast".  Well, doing that to one of the casts results in a compile error so you have to manually change the other; but what it's suggesting is this:

    if(myClass1 != myClass2)

This completely changes the output of my application from "not equal" to "equal".  What Resharper doesn't know (or doesn't care to check) is that removing those casts switches from a reference comparison to a value comparison and may have different results.  What I wrote with the original code was to test if the two references referenced the same object.  The default behaviour of a class is to do a reference check; but I've overloaded operator== (and operator !=) to perform a value comparison (I've left out the lovely bits that truly gives MyClass value semantics for clarity).

So, when Resharper offers to change your code, be sure you know side-effects of that change before you let it do it.  You could introduce a nasty bug.

kick it on DotNetKicks.com

Posted by PeterRitchie | 11 comment(s)
Filed under: , ,

Licences for Microsoft products

Occasionally I get development questions that are governed by one or more product licenses (End-User License Agreement, "EULA").  One question that I see is "I've used Reflector to decompile the .NET Framework and want to use that C# code in my application".

You've installed some Microsoft software and agreed to the EULA but didn't save it and it's nowhere on your hard-disk.  If you're not sure what your license terms are, there's a Microsoft web page that allows you to look up EULAs for many products: http://www.microsoft.com/about/legal/useterms/

 By the way, the answer to the question is "You're not licensed to do that".  Anyone know what clause in which EULA denies that?

kick it on DotNetKicks.com

Posted by PeterRitchie | 7 comment(s)
Filed under: ,

Upcoming C# 3 Guidance From Microsoft

Mircea Trofin has some design guidelines with regard to some C# 3 language additions (that I assume will make it into a revised Framework Design Guidelines of some sort).  They more less agree with the guidelines I published in Code Magazine a while ago.  There are some slight differences:

Consider using extension methods in any of the following scenarios: to provide helper functionally relevant to every implementation of an interface... and,

Do define extension methods in the same namespace as the extended type, if the type is an interface, and if the extension methods are meant to be used in most or all cases.  This applies to framework designers that are publishing interfaces but also want to publish callable methods that apply to all implementation of those interfaces.  My article approaches the guidelines more from a non-framework designer.  I do agree that extension methods to extend interfaces is very useful and is probably one of the most adept use of extension methods.  Although, I think the wording of this guideline could use improvement.

Avoid defining extension methods on System.Object, unless absolutely necessary.  Good advice.

Do not define extension methods pertaining to a feature in namespaces normally associated with other features.  Instead define them in the namespace associated with the feature they belong to, or a namespace of it.  This is really unclear (and seems to suggest contradicting the first guideline: Avoid frivolous use of the extension methods feature when defining methods on a new type.  Use the canonical, language-specific means for defining type members).  I'm assuming the jist of this is, as a framework designer, don't arbitrarily put extension methods in the namespace of the type the method applies to, consider putting the extension method in a more applicable namespace, if possible.  For example, if you want to declare an extension method "Forward" for Telecom.INode implementations, putting the method in a "Routing" namespace would be better than arbitrarily putting it in the "Telecom" namespace.  I've changed the Mircea's guidance slightly to use a interface in the example--which I think makes it more clear.

Mircea also includes Consider using extension methods in any of the following scenarios:... when object model considerations would dictate taking a dependency on some assuming but taking such a dependency would break dependency management rules.  This means, should you need to add a method to a class but adding that method would create cyclic dependency or would cause a lower level assembly/class to be dependant on a higher level class, break the method out into another assembly as an extension method.  Use this advice with caution; I would argue that if you think you need a method like this at all (even if implemented as an extension method), you likely have some design problems and should only be considered when revising a published framework, and not when creating a new framework.

Another tidbit of guidance that came about after I wrote the article and Mircea doesn't mention is that extension methods can make writing fluent interfaces much cleaner by separating the state management concern of supporting a fluent interface from the class that it applies to.

Thoughts?  Any additional guidance you feel has been overlooked (with regard to extension methods and LINQ)?

kick it on DotNetKicks.com

Single-Entry, Single-Exit, Should It Still Be Applicable In Object-oriented Languages?

Before the modern high-level languages Edsger Dijkstra came up with "Structured Programming".  This programming methodology relied on the programmer to form and enforce most of the structure of the program--manually keeping sub-structures and logic separate from one another to promote maintainability and easy of understanding, among other things.  Think assembly language with a linear collection of instructions and jumps and then the only concept of a method or function is how the rest of the logic jumps to that block of code.

This concept of delineating functions hinged on a single entry, i.e. from point A to point B only one point is actually jumped to from "external" code.  This single entry concept usually included a single exit, to ease the delineation of a "function".  This is known as the single-entry, single-exit methodology (SESE).

It's hard to think of multiple entry points with modern high-level languages what with object-orientation and abstraction and encapsulation; but it's easy to see multiple exits from a method.  For example:

        public static int CountCommas(string text)

        {

            if (String.IsNullOrEmpty(text))

            {

                return 0;

            }

            if (text.Length == 0)

            {

                return 0;

            }

 

            int index = 0;

            int result = 0;

            while (index > 0)

            {

                index = text.IndexOf(',', index);

                if (index > 0)

                {

                    result++;

                }

            }

            return result;

        }

Structured programming (at least SESE) suggests writing the method like this instead:

        public static int CountCommas(string text)

        {

            int result = 0;

            if (!String.IsNullOrEmpty(text))

            {

                if (text.Length > 0)

                {

                    int index = 0;

                    while (index > 0)

                    {

                        index = text.IndexOf(',', index);

                        if (index > 0)

                        {

                            result++;

                        }

                    }

                }

            }

 

            return result;

        }


This concept may have made for more readable code when Dijkstra first cemented the concept in the late 60's early 70's; but in Object-Oriented languages I believe it's less readable.  For one thing, it's difficult to shoe-horn SESE with other language concepts like exceptions:

        public static int CountCommas(string text)

        {

            Exception exception = null;

            int result = 0;

            if (!String.IsNullOrEmpty(text))

            {

                if (text.Length > 0)

                {

                    int index = 0;

                    while (index > 0)

                    {

                        index = text.IndexOf(',', index);

                        if (index > 0)

                        {

                            result++;

                        }

                    }

                }

                else

                {

                    exception = new ArgumentException("argument of zero length", "text");

                }

            }

            else

            {

                exception = new ArgumentNullException("text");

            }

 

            if (exception != null)

            {

                throw exception;

            }

 

            return result;

        }


And this technically still violates SESE since we exit via return or via throw, although they have close proximity.

I believe the above example is hard to read and hard to maintain.  I would abandon the SESE trappings of structured programming in favour of:

 

        public static int CountCommas(string text)

        {

            if (String.IsNullOrEmpty(text))

            {

                throw new ArgumentNullException("text");

            }

            if (text.Length == 0)

            {

                throw new ArgumentException("argument of zero length", "text");

            }

 

            int index = 0;

            int result = 0;

            while (index > 0)

            {

                index = text.IndexOf(',', index);

                if (index > 0)

                {

                    result++;

                }

            }

            return result;

        }

In high-level languages that do have concepts like functions, subroutines, or methods, the "Single Entry" aspect of SESE is moot, evolving to the concept of "Single Exit" or the "Single Point of Exit From Methods Principle".  This seems like a Cargo Cult to me--separating the part of a concept that is no longer obviously archaic in the hopes of getting the same result in a different context.

Interestingly, as I was writing this, Patrick Smacchia posted to his blog about NDepend and Nesting Depth--which basically details metrics that show the SESE implementations I show above would actually have higher nesting depths than the non-SESE implementations and thus be more complex, less readable, and less testable.

 What are your thoughts?  Do you generally follow Single Point of Exit From Methods Principle?  If you do, do you ignore it for exceptions?

kick it on DotNetKicks.com