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).