ThinkGeek - Cool Stuff for Geeks and Technophiles

Pipelining can be a useful operation when you need to break up code into several steps, perhaps for readability. Typically this is done to avoid a huge mess of nested functions: f(g(h(i(j(k(l(x)))))). Without pipelining you typically need to assign the various steps to local variables. You can get pipelining in C# by extending object with this extension method:

public static TResult Pipe<T, TResult>(this T obj, Func<T, TResult> f)
{
   return f(obj);
}

Example calculating standard deviation with and without pipelining:


List<double> values = new List<double>() { 1, 7, 8, 9, 10, 100, 1000, 1001, 100000 };

double average = values.Average();
double totalVariance = 0;
foreach (double value in values)
{
   totalVariance += Math.Pow(value - average, 2);
}

//OR you could do this:
//totalVariance = values.Aggregate(0.0, (variance, val) => variance + Math.Pow(val - average, 2));

double stdDeviation = Math.Sqrt(totalVariance / values.Count);

//Now with pipe
stdDeviation = values
   .Pipe(v => v.Average())
   .Pipe(avg => values.Aggregate(0.0, (variance, val) => variance + Math.Pow(val - avg, 2)))
   .Pipe(totVariance => Math.Sqrt(totalVariance / values.Count));

Even int gets Pipe():

(2)
   .Pipe(i => Math.Pow(i, 42))
   .Pipe(i42 => Math.Sin(i42));

The benefit, as far as I’m concerned, is avoiding uncessary mutable variables in the function scope (or at least from leaking out to where they don’t need to be).

4 Responses to “C# Pipelining: Extend Object With Pipe”

  1. Chris says:

    If delegate-invoke didnt suck so much performance-wise, this would be nice.

    • Mark says:

      No. Map typically deals with a sequence of things. In LINQ the equivalent is IEnumerable.Select. Pipe does not require a sequence or IEnumerable.

  2. Hopefully not says:

    @dm3: not quite – the LINQ equivalent of map is Select, and the LINQ equivalent of fold is Aggregate which he has used

    the LINQ version of this is:

    var std = Math.Sqrt((from v in values
    let avg = values.Average()
    select Math.Pow(v – avg, 2)).Average());

    which benefits a lot from LINQ having Average built in.