Elegant Inline Debug Tracing

As much fun as it is to step through code with a debugger, I usually prefer to use System.Diagnostics.Debug and Trace with DebugView to see what’s happening in realtime. This is particularly handy to track intermediate results in higher-order functions that you might not be able to step into. However, it’s not always convenient to insert debugging statements amongst the composed expressions of F#, PowerShell or LINQ.

An alternative first came to mind while working in F#:

let dbg x = System.Diagnostics.Debug.WriteLine(x |> sprintf "%A"); x

(Read |> as “as next parameter to”.) We can then use this function anywhere to peek at a value, perhaps an intermediate list in this trivial example:

let data = [1..10]
           |> List.filter (fun i -> i%3 = 0) |> dbg
           |> List.map (fun i -> i*i)

Indeed [3; 6; 9] are traced as multiples of three. Not a particularly convincing example, but it should be pretty easy to imagine a more complex algorithm for which unintrusive tracing would be useful.

This works pretty well with F#’s |> operator to push values forward, but what about C#? Given my posting history, it shouldn’t be hard to guess where I’m going with this…

Extension Methods

So if |> is “as next parameter to”, the . of an extension method call might read “as first parameter to”. So we can implement a roughly equivalent function (sans F#’s nice deep-print formatter "%A") like so:

    public static T Debug<T>(this T value)
    {
        Debug.WriteLine(value);
        return value;
    }

    public static T Dbg<T>(this T value, string category)
    {
        Debug.WriteLine(value, category);
        return value;
    }

I find the optional label handy to keep different traces separate. Looking again, there’s an overload that accepts a category, so we’ll use that instead. So why might this be useful? Maybe we want to log the value assigned within an object initializer:

var q = new SPQuery() {
  Query = GetMyQuery().Debug("Query")
};

Rather than store the query string to a temporary variable or retrieve the property after it’s been set, we can just trace the value inline. Or consider a LINQ example:

var items = from SPListItem item in list.GetItems(q)
            let url = new SPFieldUrlValue(item["URL"] as string)
            where url.Url.Debug("URL").StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase)
            select new
            {
                Title = item.Title.Debug("Title"),
                Description = url.Description,
            };

Here we log all URLs that pass through, even the ones excluded from the result by the predicate. This would be much harder to implement efficiently without inline logging.

This technique works great for simple objects with a useful ToString(), but what about more complex objects? As has often been the answer lately, we can use higher-order functions:

    public static T Dbg<T, R>(this T value, Func<T, R> selector)
    {
        Debug.WriteLine(selector(value));
        return value;
    }

    public static T Dbg<T, R>(this T value, string category, Func<T, R> selector)
    {
        Debug.WriteLine(selector(value), category);
        return value;
    }

Now we can provide a delegate to trace whatever we want without affecting the object itself. For example, we can easily trace a row count for the DataView being returned:

public DataView GetResults()
{
    var myTable = GetDataTable();
    // Process data...
    return myTable.DefaultView.Dbg("Result Count", v => v.Count);
}

I could go on, but you get the idea.

PowerShell Filter

Finally, we can implement similar functionality in PowerShell using a filter with an optional scriptblock parameter:

filter Debug([scriptblock] $sb = { $_ })
{
  [Diagnostics.Debug]::WriteLine((& $sb))
  $_
}

PS > 1..3 | Debug { $_*2 } | %{ $_*$_ }
1
4
9

Which traces 2, 4, 6, as expected.

Update 4/19/2009: Changed functions to use category overloads. And another point to consider: if the value being traced could be null, selector should be designed accordingly to avoid NullReferenceException. There’s nothing worse than bugs introduced by tracing or logging.

More SharePoint Higher-Order Functions

Though I haven’t actually used the term before, I’ve discussed a number of higher-order functions in the past. Simply put, a higher-order function either accepts a function as a parameter, returns a function, or both. The terminology might be foreign, but the technique is used all over the place:

Another use of higher-order functions is to ensure the existence of a SharePoint resource. For example, I often need to fetch a SharePoint list and create it if doesn’t exist. A standard implementation might look something like this:

public static SPList GetOrCreateList(this SPWeb web, string listName,
                                     string description, SPListTemplate template)
{
    SPListCollection webLists = web.Lists;
    SPList list = webLists.Cast<SPList>()
                          .FirstOrDefault(l => l.Title == listName);
    if (list == null)
    {
        Guid newListID = webLists.Add(listName, description, template);
        list = webLists[newListID];
    }
    return list;
}

While there’s nothing wrong with this implementation, per se, it’s not exceedingly flexible. What if we want to use a different overload of SPListCollection.Add? What if we need to elevate privileges to create the list? We could certainly create a dozen variations based on this pattern, but that’s a bunch of duplicate code that we would much rather avoid. Instead, we can use a single higher-order function:

public static SPList GetOrCreateList(this SPWeb web, string listName,
                                     Func<SPWeb, string, SPList> listBuilder)
{
    SPList list = web.Lists.Cast<SPList>()
                     .FirstOrDefault(l => l.Title == listName);
    if(list == null && listBuilder != null)
        list = listBuilder(web, listName);
    return list;
}

And then specify exactly how the list should be created. We could redefine our original method like this:

public static SPList GetOrCreateList(this SPWeb web, string listName,
                                     string description, SPListTemplate template)
{
    return GetOrCreateList(web, listName, (builderWeb, builderName) =>
    {
        var builderLists = builderWeb.Lists;
        Guid newListID = builderLists.Add(builderName, description, template);
        return builderLists[newListID];
    });
}

Or we can just as easily specify a builder that uses elevated privileges and a different Add overload:

public static SPList GetOrCreateTasksList(this SPWeb web)
{
    return GetOrCreateList(web, "Tasks", (builderWeb, builderName) =>
    {
        Guid newListId = web.SelectAsSystem(sysWeb =>
            sysWeb.Lists.Add(builderName, null, SPListTemplateType.Tasks));

        return builderWeb.Lists[newListId];
    });
}

Or my preference is to define a (testable) builder method and just use the higher-order function without a wrapper:

private static SPList CreateGenericList(SPWeb web, string name)
{
    var id = web.Lists.Add(name, null, SPListTemplateType.GenericList);
    return web.Lists[id];
}

void DoSomething(SPWeb web)
{
    SPList list = web.GetOrCreateList("Some List", CreateGenericList);
    if (list == null)
        throw new SPException("Some List does not exist and could not be created.");
    // Do something
}

GetOrCreateGroup

Another use for this pattern is the creation of SharePoint groups, inspired by Adam Buenz’s recent post. His code is correct (though I believe an ordinal comparison is more appropriate than invariant culture), but it can’t easily handle scenarios requiring elevation, AllowUnsafeUpdates, etc. Instead, we can define a higher-order function like this:

public static SPGroup GetOrCreateGroup(this SPWeb web, string groupName,
                                       Func<SPWeb, string, SPGroup> groupBuilder,
                                       Action<SPWeb, SPGroup> associateGroup)
{
    SPGroup group = web.SiteGroups.Cast<SPGroup>()
                        .FirstOrDefault(g =>
                            string.Equals(g.Name, groupName,
                                StringComparison.OrdinalIgnoreCase));
    if (group == null && groupBuilder != null)
        group = groupBuilder(web, groupName);
    if (group != null && associateGroup != null)
        associateGroup(web, group);
    return group;
}

With which the original method is easily rewritten:

public static SPGroup GetGroupOrCreate(SPWeb web, string name,
                                       string description, SPUser owner,
                                       SPUser defaultUser, bool associate)
{
    return web.GetOrCreateGroup(name,
        (builderWeb, builderName) =>
        {
            var builderGroups = builderWeb.SiteGroups;
            builderGroups.Add(builderName, owner, defaultUser, description);
            return builderGroups[name];
        },
        (assocWeb, assocGroup) =>
        {
            if (associate && !assocWeb.AssociatedGroups.Contains(assocGroup))
            {
                web.AssociatedGroups.Add(assocGroup);
                web.Update();
            }
        });
}

Again, the advantage is that we can easily tweak how the group is created and associated independent from the common get-or-create logic.