Have language features changed the way we work for the better?

Craig Murphy dropped a little coding challenge on his blog the other day. This prompted me to write the responses as below. I’ve tried to target each one towards using a particular technology as the framework has developed.

Have a look and tell me which is your preferred answer, or propose a new one (but again try to target a language feature). I’d love to know who you why you choose that language feature over another.

Option 1. With Linq

private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
 
static void Main(string[] args)
{
    char c = Console.ReadKey().KeyChar;
 
    var myChars = from character in alphabet
                  where character <= c
                  select character;
 
    var fullRow = myChars.Skip(1).Reverse().Concat(myChars);
 
    var myRows = (from character in myChars
                  select ConvertToSpaces(character, fullRow));
 
    var reverseRows = myRows.Reverse().Skip(1);
    myRows = myRows.Concat(reverseRows);
 
    Console.WriteLine(Environment.NewLine);//Skip the ReadKey line
    foreach (string line in myRows)
        Console.WriteLine(line);
 
    Console.ReadKey();
}
 
private static string ConvertToSpaces(char wanted, IEnumerable<char> characters)
{
    return new string(
    (from character in characters
     select character == wanted ? character : ' ').ToArray());
}

Option 2. With Generics

 
class Program
  {
      private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
 
      static void Main(string[] args)
      {
          char c = Console.ReadKey().KeyChar;
 
          List<char> myChars = new List<char>();
          foreach (char character in alphabet)
          {
              if (character <= c)
                  myChars.Add(character);
          }
 
          List<char> temp = new List<char>(Reverse<char>(AllButFirst<char>(myChars)));
          temp.AddRange(myChars);
          string fullRow = new string(temp.ToArray());
 
          List<string> myRows = new List<string>();
          foreach (char character in myChars)
          {
              myRows.Add(ConvertToSpaces(character, fullRow));
          }
 
          IEnumerable<string> reverseRows = AllButFirst<string>(Reverse<string>(myRows));
          myRows.AddRange(reverseRows);
 
          Console.WriteLine(Environment.NewLine);//Skip the ReadKey line
          foreach (string line in myRows)
              Console.WriteLine(line);
 
          Console.ReadKey();
      }
 
      private static IEnumerable<T> Reverse<T>(IEnumerable<T> myChars)
      {
          Stack<T> reverse = new Stack<T>();
          foreach (T character in myChars)
          {
              reverse.Push(character);
          }
          while (reverse.Count > 0)
          {
              yield return reverse.Pop();
          }
      }
 
      private static IEnumerable<T> AllButFirst<T>(IEnumerable<T> myChars)
      {
           bool first = true;
          foreach (T character in myChars)
          {
              if (first)
                  first = false;
              else
                  yield return character;
          }
      }
      
 
      private static string ConvertToSpaces(char wanted, IEnumerable<char> characters)
      {
          StringBuilder result = new StringBuilder();
          foreach (char character in characters)
          {
              result.Append(character == wanted ? character : ' ');
          }
          return result.ToString();
      }
  }

Option 3. Using IEnumerable

 

class ProgramDNv2
{
    private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
        
    static void Main(string[] args)
    {
        DiamondChars diamond = new DiamondChars();
        diamond.chars = GetChars(     Console.ReadKey().KeyChar);
        foreach (string line in diamond)
        {
            Console.WriteLine(line);
        }
        Console.ReadKey();
    }
 
        private static string GetChars(char MidChar)
        {
            string chars = alphabet.Substring(0, alphabet.IndexOf(MidChar) + 1);
            return chars;
        }
 
    private class DiamondChars : IEnumerable<String>
    {
        public string chars;
 
        #region IEnumerable<string> Members
 
        public IEnumerator<string> GetEnumerator()
        {
            int index = 0;
            foreach (char character in chars)
            {
                yield return MakeLine(character, index);
                index++;
            }
            
            index--;
            foreach (char character in chars.Reverse())
            {
                if (index < chars.Length - 1)
                {
                    yield return MakeLine(character, index);
                }
                index--;
            }
        }
 
        #endregion
 
        private string MakeLine(char character, int index)
        {
            string line = new string(chars[index], 1).PadLeft(chars.Length - index);
 
            if (index > 0)
                 return line + new string(chars[index], 1).PadLeft(index * 2);
            else
                 return line;
        }
 
        #region IEnumerable Members
 
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
 
        #endregion
    }
 
}

Option 4. Simple recursion

 
    class ProgramDNv1
    {
        static void Main(string[] args)
        {
            string input = "abcde";
            StringBuilder result = new StringBuilder();
            BuildDiamond(0, input, result);
            Console.WriteLine(result);
        }
 
 
 
        private static void BuildDiamond(int index, string input, StringBuilder result)
        {
            string line = new string(input[index], 1).PadLeft(input.Length - index);
            string line2 = new string(input[index], 1).PadLeft(index * 2);
            result.Append(line);
            if (index > 0)
                result.Append(line2);
            result.Append(Environment.NewLine);
            if (index < input.Length - 1)
            {
                BuildDiamond(index + 1, input, result);
                result.Append(line);
                if (index > 0)
                    result.Append(line2);
                result.Append(Environment.NewLine);
            }
        }
    }

Now add a quick comment below telling you preferred implementation and briefly why. Thanks.

Advertisements

Providing extensible classes: An alternative to inheritance and events

I have a list that is cached. When I come to refresh the list I don’t want to just throw it away and start again, so I use the following.
private void UpdateChildren(IEnumerable<Guid> fromDb, IEnumerable<Model> cached )
{
    List<Model> unseen = new List<Model>(cached); 
 
    foreach (Model child in cached)
    {
        Guid childID = child.Id;
        if (fromDb.Contains(childID) == false)
            cached.Add(CreateModel(childID));
        //seen it now
        unseen.Remove(child);  
    }
    //Delete missing items
    foreach (Model child in unseen)
    {
        DisposeModel(child);
        cached.Remove(child);
    }
}
 
private void DisposeModel(Model child)
{
    // Maybe do nothing
} 
 
private Model CreateModel(Guid child)
{
    return new Model(child);
} 

This works fine but it isn’t very generic. Let’s make some changes

Creating a class

Currently this isn’t really a class, it could be expressed as three static methods. By including the cached list we can start to provide a reusable class with state.

class CachedCollection
{
    private List<Model> _cached = new List<Model>();
 
    private void UpdateChildren(IEnumerable<Guid> fromDb)
    {
        List<Model> unseen = new List<Model>(_cached); 
 
        foreach (Model child in _cached)

Mapping from Guid to Model

Currently we know how to compare a Guid and a Model, since the model has a property that exposes that Guid again. We cannot be certain that this so the case every time so now we need to go for a more generic pairing. In this case I suggest moving from a List<Model> to a Dictionary<Guid, Model>.

 

private Dictionary<Guid, Model> _known = new Dictionary<Guid, Model>();
public void UpdateItems(IEnumerable<Guid> iEnumerable)
{
    ...
    foreach (Model item in iEnumerable)
    {
        if (_known.ContainsKey(item))

Now our paired relationship is completely external to the classes themselves. This is a common feature of code that has been made reusable, in that the method of relating things is sub optimal, in this case with a memory overhead. The dictionaries key hashing lookup will provide a performance boost whether that is required for this application or not.

Applying Generic types

Not much makes a code more generic than applying Generic types, in this case we can refactor the fixed types, but this is full of issues. In this case lets consider converting the Guid to TActual and the Model to TDesired

private Model CreateModel(Guid child)
{
    return new Model(child);
}

If we look at the CreateModel method we note that this is currently creating a new TDesired from a TActual. We can add a new constraint to the the class defintion, but I don’t know of a way to specify that a Type has a particular constructor that takes a single argument.

//Just gets me a ') expected' error.
class CachedCollection<TActual, TDesired> where TDesired:new(TActual)

I can of course make my class abstract and leave it to the derivation to handle, but that means I need a derived class.

abstract class CachedCollection<TActual, TDesired> 
{
    private List<Model> _cached = new List<Model>();
 
    private void UpdateChildren(IEnumerable<TActual> fromDb)
    {
        List<TDesired> unseen = new List<TDesired>(_cached); 
 
        foreach (TDesired child in _cached)
        {
            TActual childID = child.Id;
            if (fromDb.Contains(childID) == false)
                _cached.Add(CreateModel(childID));
            //seen it now
            unseen.Remove(child);  
        }
        //Delete missing items
        foreach (TDesired child in unseen)
        {
            DisposeModel(child);
            _cached.Remove(child);
        }
    }
 
    private abstract void DisposeModel(TDesired child);
    private abstract TDesired CreateModel(TActual child);
}

Of course when we consider using abstract and virtual methods, we start to consider functions as pieces of code that can be referred to. Before DotNet 2.0 there the only way to do this was to use delegates. Now where these functions are optional you may see them exposed as events. These days we have some alternatives.

Generic delegates

There are three great Generic delegate types available since DotNet 2.0

//http://msdn.microsoft.com/en-us/library/kt456a2y.aspx
public delegate TOutput Converter<TInput, TOutput>(TInput input)
 
//http://msdn.microsoft.com/en-us/library/system.action.aspx
public delegate void Action<T>(T input)
 
//http://msdn.microsoft.com/en-us/library/bfcke1bz.aspx
public delegate bool Predicate<T>(T input)
 
These are great building blocks and along with 3.5’s lambda syntax let us provide functions almost as simply as by deriving a class. For example we can convert
private abstract TDesired CreateModel(TActual child);
public void Update()
{
    ...
    x = CreateModel(...);
    ...
}
Into
private Converter<TActualItem, TAlternateItem> _createAlternateItem 
    = new Converter<TActualItem, TAlternateItem>(
        (TActualItem actual) => {throw new NotImplementedException();}
    );
 
public void Update()
{
    ...
    x = _createAlternateItem (...);
    ...
}

Conclusion

For me, this is very powerful. It means we can take our original example and produce the following non-abstract class.

class CollectionSync<TActualItem, TAlternateItem>
{
    public CollectionSync(Converter<TActualItem, TAlternateItem> createAlternateItem)
    {
        _createAlternateItem = createAlternateItem;
    }
 
    public CollectionSync(Converter<TActualItem, TAlternateItem> createAlternateItem, 
        IEnumerable<TActualItem> list) 
        : this(createAlternateItem)
    {
        foreach (TActualItem actual in list)
        {
            _known.Add(actual, _createAlternateItem(actual));
        }
    }
 
    private Dictionary<TActualItem, TAlternateItem> _known 
        = new Dictionary<TActualItem, TAlternateItem>();
    private Converter<TActualItem, TAlternateItem> _createAlternateItem = null;
    private Action<TAlternateItem> _disposeAlternate 
        = new Action<TAlternateItem>((TAlternateItem alternate) => { });
    private Action<KeyValuePair<TActualItem, TAlternateItem>> _udateSingleAlternate 
        = ((KeyValuePair<TActualItem, TAlternateItem> kvp) => { });
 
    public void UpdateItems(IEnumerable<TActualItem> iEnumerable)
    {
        List<TActualItem> unseen = new List<TActualItem>(_known.Keys);
 
        foreach (TActualItem item in iEnumerable)
        {
            if (_known.ContainsKey(item))
            {
                _udateSingleAlternate(
                    new KeyValuePair<TActualItem, TAlternateItem>
                        (item, _known[item]));
                unseen.Remove(item);
            }
            else
            {
                TAlternateItem newLVI = _createAlternateItem(item);
                _known[item] = newLVI;
            }
        }
        //Delete missing items
        foreach (TActualItem item in unseen)
        {
            _disposeAlternate(_known[item]);
            _known.Remove(item);
        }
    }
}