Wednesday, October 23, 2013

Learning C# via Katas - Part 2 - Extension Methods

This is part 2 in a series of blog posts exploring CSharpKatas, a new GitHub project and training tool I put together.  The Katas teach C# newcommers how to apply advanced language features, how to write idiomatic C#, and most importantly how to avoid Java idioms.

If It Types Like a Duck


Kata #1 introduced the reader to LINQ and some replacements for loops and if statements.  Kata #2 focuses on a feature typically found in dynamic languages that allows adding methods to other people's classes without modifying or subtyping the class.  The feature, called extension methods, introduces to C# elements of a feature known as "duck typing" found in languages such as Ruby or JavaScript.

Duck typing is a style of typing in which an object's methods and properties determine the valid semantics, rather than its inheritance from a particular class or implementation of a specific interface. The name of the concept refers to the duck test, attributed to James Whitcomb Riley, which may be phrased as follows:
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck

Unlike with dynamic languages, however, C#'s extension methods are implemented via some fancy compiler trickery.  The details of the trickery is captured in the third todo in the Kata in which the reader is asked to reverse engineer the Intermediate Language (IL) code after compiling the solution.  This final todo will also add a powerful tool to the reader's toolbelt.

Caveats and Limitations


Due primarily to the compiler trickery mentioned above extension methods have drawbacks over what dynamic language aficionados would likely expect.  For instance isn't possible to add static methods onto other people's classes.  Additionally, one can't add properties to external classes.  This last limitation has frustrated me on more than one occasion.

Another limitation is that extension methods require both knowing the namespace an extension method is defined in, and adding a related using statement.  This limitation can make it hard for others to discover your extension methods.  It can also decrease readability as it can be difficult to determine where a method actually lives.

Finally a caveat: it can be easy to over use extension methods after first learning of them.  For instance just because you could add a SpellCheck() method onto C#'s String class, would you really want this in your code:

foreach (var error in "I'm a bad speller".SpellCheck())
{
    // The above is a bad idea, please don't do it
}

Kata #2


With the caveats and drawbacks out of the way here is a copy of the second Kata:

using System.Collections.Generic;
using NUnit.Framework;

namespace CSharpKatas
{
    // todo #1: Without modifying SomeoneElsesClass add a new class that 
    //     makes the unit tests pass
    // todo #2: Refactor so that there are no loops or if statements.
    // todo #3: (see below)


    #region DoNotModify
    // DO NOT MODIFY THIS CLASS
    public class SomeoneElsesClass
    {
        public List<int> Numbers { get; set; }
    }
    #endregion

    [TestFixture]
    public class TestExtensionMethods
    {
        [Test]
        public void FindNumberOrDefault_NumberExists_ReturnIt()
        {
            var someoneElsesClass = new SomeoneElsesClass
            {
                Numbers = new List<int> { 1, 2, 3 }
            };
            Assert.AreEqual(1, someoneElsesClass.FindNumberOrDefault(1));
        }

        [Test]
        public void FindNumberOrDefault_NumberDoesNotExist_ReturnNull()
        {
            var someoneElsesClass = new SomeoneElsesClass
            {
                Numbers = new List<int> { 1, 2, 3 }
            };
            var v = someoneElsesClass.FindNumberOrDefault(4);
            Assert.IsNull(v);
        }

        [Test]
        public void FindNumberOrDefault_SomeoneElsesClassIsNull_CheckForNull()
        {
            // todo #3: What's bizarre about the following test? Why is there 
            //    no error? Consider reverse engineering the code with a tool 
            //    like Just Decompile to get the answer.
            SomeoneElsesClass someoneElsesClass = null;
            Assert.IsNull(someoneElsesClass.FindNumberOrDefault(4));
        }
    }
}


Summary


I hope you find these Kata's fun and enlightening and that you find my enthusiasm for the C# language contagious.  Enjoy!  And feel free to ask questions in the comments here or @lprichar on twitter.

Wednesday, October 16, 2013

C# Isn't Java - Learning via Katas - Part 1

CSharpKatas is a new GitHub project and training tool I put together.  It teaches C# newcommers how to apply advanced language features, how to write idiomatic C#, and most importantly how to avoid Java idioms.


C# Isn't Java


C# is at least a decade ahead of Java, and that's being generous.  Sadly many junior, ex-Java, and even some seasoned C# developers continue to use Java idioms in C# and think of the two as equivalent.  I've overheard "C# is just like Java" more times than I care to recall, and it makes me angry every time.

If you too become frustrated hearing these similes and need a resource, or you find yourself on a C# project with Java coders, or you could just use a refresher on writing idiomatic C#, then CSharpKatas is for you and/or your team.  I hope you enjoy and that it becomes a valuable resource for you and the C# community.

Java is Blub


Why do people confuse Java with C# to begin with?  Partly this is Paul Graham's Blub Paradox at work:

Blub is a hypothetical programming language … As long as our hypothetical Blub programmer is looking down the power continuum, he knows he's looking down. Languages less powerful than Blub are obviously less powerful, because they're missing some feature he's used to. But when our hypothetical Blub programmer looks in the other direction, up the power continuum, he doesn't realize he's looking up. What he sees are merely weird languages. He probably considers them about equivalent in power to Blub, but with all this other hairy stuff thrown in as well. Blub is good enough for him, because he thinks in Blub.

Java is Blub and C# the more powerful language.  C#'s power is derived from the huge array of language features it has that Java lacks (and that Java won't have for at least a decade if ever).  Some of these features include:


Those that equate C# and Java are likely unfamiliar with many of the features listed above.  Should they happen to run into code that, for example, uses a method missing catch-all (aka TryInvokeMember) they just see weird constructs and "hairy stuff" and assume incorrectly that C# is equivalent with Java.

C#'s Beauty Revealed


My lofty goal is first, to put a stop to the misconception that "C# is just like Java" and second, to encourage C# newcomers to write idiomatic C#.  To accomplish this I put together a set of Code Katas, or mind exercises that I published in a github project.

Each Kata consists of a set of failing unit tests and some to do's.  The problems are generally extracted from real problems I've had to solve and are designed to introduce new concepts gradually.  Developers are asked to turn the tests green using any means necessary, then refactor using C# idioms (such as not writing loops or if statements without good reason).  The exercises assume a solid working knowledge of an OO language such as Java and an ability to look stuff up in the documentation.

Perhaps along the way developers will become convinced of how wonderful TDD and Red-Green-Refactor is, but that's incidental.

Now if you're more of a book learner, or just want more depth, I would highly encourage you to read Jon Skeet's awesome book C# In Depth.

Or if, like me, you're more a hands-on learner I would encourage you to follow along at home by branching or pulling my CSharpKatas project and trying to solve the problems in your own branch.  If solving a Kata takes more than a few minutes I recommend you delete your solution and do it again until solving it is second-nature.

Finally, there are no solutions published.  If there is demand I may publish my solutions, but the "to do"'s should be sufficient.

Kata #1


The objectives of the first Kata:

  • Learn to run C# unit tests
  • Learn basic alternatives to loops and foreach statements
  • Learn how to use lambdas and some LINQ to Objects

Without further ado here is a copy of first Kata:

using NUnit.Framework;

namespace CSharpKatas
{
    public class Calculator
    {
        public int SumNumbers(int start, int count)
        {
            // todo #1: Get all the tests passing
            // todo #2: Refactor so there are no loops or if statements (this
            
//    is the functional approach and is idiomatic for C#)
            // todo #3: Refactor to use the Aggregate() LINQ method            
            //    see 101 Linq Samples)
            return 0;
        }
    }

    [TestFixture]
    [Ignore]
    public class Test
    {
        [Test]
        public void SumNumbers_StartAt100SumNext1_TotalIs100()
        {
            var kata = new Calculator();
            Assert.AreEqual(100, kata.SumNumbers(100, 1));
        }

        [Test]
        public void SumNumbers_StartAt100SumNext2_TotalIs201()
        {
            var kata = new Calculator();
            Assert.AreEqual(201, kata.SumNumbers(100, 2));
        }
        [Test]
        public void SumNumbers_StartAt100SumNext0_TotalIs0()
        {
            var kata = new Calculator();
            Assert.AreEqual(0, kata.SumNumbers(100, 0));
        }

        [Test]
        public void SumNumbers_StartAt0SumNext0_TotalIs0()
        {
            var kata = new Calculator();
            Assert.AreEqual(0, kata.SumNumbers(0, 0));
        }

        [Test]
        public void SumNumbers_StartAt0SumNext3_TotalIs3()
        {
            var kata = new Calculator();
            Assert.AreEqual(3, kata.SumNumbers(0, 3));
        }

        [Test]
        public void SumNumbers_StartAt0SumNext100_TotalIs5050()
        {
            var kata = new Calculator();
            Assert.AreEqual(5050, kata.SumNumbers(1, 100));
        }
    }
}


Conclusion


I hope you find these Kata's fun and enlightening and that you find my enthusiasm for the C# language contagious.  Enjoy!  And feel free to ask questions in the comments here or @lprichar on twitter.