Stu Smith: Making It Up As I Go Along“ My life working for BinaryComponents, coding, design, and other stuff. ”
Lee and I are working on a project at the moment, and we got into a mini-argument about how best to write a tiny piece of code. Essentially, we're working with a thrid-party API that returns some data as key/value pairs in a hastable: the keys are always strings, but the values can be either strings, or further hashtables. (So essentially we have a tree structure). For the purposes of this discussion, we need to render that tree as XML.
Here's the "traditional" method of accomplishing this:
public static XDocument ConvertDictionaryToXml( IDictionary dictionary )
{
XElement root = new XElement( "root" );
ConvertDictionaryToXml( root, dictionary );
return new XDocument( root );
}
public static void ConvertDictionaryToXml( XElement parent, IDictionary dictionary )
{
foreach( DictionaryEntry kv in dictionary )
{
XElement newElement = new XElement( kv.Key.ToString() );
if( kv.Value is IDictionary )
{
ConvertDictionaryToXml( newElement, (IDictionary)kv.Value );
}
else
{
newElement.Value = kv.Value.ToString();
}
parent.Add( newElement );
}
}
Now I disagree with this - it's my belief that loops should go the way of the "goto" statement and be consigned to history. Here's my version:
public static XDocument ConvertDictionaryToXml( IDictionary dictionary )
{
var root = new XElement( "root", DictionaryToXElement( dictionary ) );
return new XDocument( root );
}
private static XElement[] DictionaryToXElement( IDictionary sourceDictionary )
{
var xelements = from DictionaryEntry p in sourceDictionary
let dp = p.Value as IDictionary
select (dp == null)
? new XElement( p.Key.ToString(), p.Value.ToString() )
: new XElement( p.Key.ToString(), DictionaryToXElement( dp ) );
return xelements.ToArray();
}
Short and sweet. No (visible) changing state to understand, just a recursive sequence transform. I see parallels here in the new WPF model of animation: in the older WinForms, to animate something, you'd set up a timer and repeatedly change it. In the newer WPF, you simply set up the intent of the animation, and the system handles the messy updating stuff.
I see it as a natural progression in the power of languages:
(Incidentally, I'm well aware of the similarities to languages like LISP or Haskell - and if you think LISP is old-fashioned, you should probably have a read of Structure and Interpretation of Computer Programs).
If you're worried about performance, well, I guess there could be a hit with my version, you'd have to profile it, but on the other hand the LINQ version would parallelize nicely using PLINQ, something that can't be said for arbitrary for-loops. (Of course, if we were worried about performance, we wouldn't be using XML).