Frostware.Pipe 1.0.0

dotnet add package Frostware.Pipe --version 1.0.0
NuGet\Install-Package Frostware.Pipe -Version 1.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Frostware.Pipe" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Frostware.Pipe --version 1.0.0
#r "nuget: Frostware.Pipe, 1.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Frostware.Pipe as a Cake Addin
#addin nuget:?package=Frostware.Pipe&version=1.0.0

// Install Frostware.Pipe as a Cake Tool
#tool nuget:?package=Frostware.Pipe&version=1.0.0

Frostware.Pipe

A lightweight piping library for C#

Table of contents

Why Piping?

In computer programming, a pipe is a technique for passing information from one program process to another. A pipe passes a parameter such as the output of one process to another process which accepts it as input. The system temporarily holds the piped information until it is read by the receiving process.

This is useful because it allows us to write more readable code that requires less temporary variables.

Consider this example:

//prints "2" to the console
Console.WriteLine(MathF.Round(1.7f));

Here we are rounding 1.7, then printing the result to the console. Which is fine, but there are 2 main problems with this.

  1. The order of operations is the opposite of how it is read.
  2. Once this gets more complicated, it get's harder to keep track of what is going on. To combat this, it is common to cache intermediate states in order to maintain readability

Instead, we could use a pipe:

1.7f
   .Pipe(MathF.Round) // returns 2f
   .Pipe(Console.WriteLine); //Prints "2" in the console

Now, the operations are executed the way they are read and the logic is easier to follow and there is no longer a need to cache values for readability's sake.

Basics

Frostware.Pipe extends all objects with the Pipe method whether it be a string, an int or a class. Everything can be piped.

"Hello".Pipe()
2.Pipe()
new Foo().Pipe()

The simplest form of pipe is the lambda pipe.

var result = "Hello"
     .Pipe(hello => hello + " World"); // returns "Hello World"

var result = 2
     .Pipe(two => two + 2); // returns 4

Pipes can be chained any amount of times, the result of the first being piped into the input of the next.

var result = 3f
    .Pipe(x => x / 2) // returns 1.5f
    //x here is 1.5f
    .Pipe(x => MathF.Round(x)); // returns 2f

Which is pretty cool, but this can be simplified.

Since the Pipe methods take in an Action or a Func, that means we can pass in methods that match the function signature. In the case above, the second pipe takes in a float, so we can pass any 1 parameter method that takes in a float.

MathF.Round has an overload that takes in 1 float, which means we can do this:

var result = 3f
    .Pipe(x => x / 2) // returns 1.5f
    //the pipe will pass 1.5f into MathF.Round implicitly
    .Pipe(MathF.Round); // returns 2f

Console.WriteLine() also takes in a float, so we can take the result of our rounding and print it to the console.

3f
    .Pipe(x => x / 2f) // returns 1.5f
    .Pipe(MathF.Round) // returns 2f
    .Pipe(Console.WriteLine); //Prints "2" in the console

Multi pipes

Multi pipes allow you to use a tuple to pipe multiple arguments at the same time.

//the tuples are mapped to the arguments in order

var result = (x: 1.75f, digits: 1)
    //this is equivalent to MathF.Round(x: 1.15f, digits: 1)
    .Pipe2(MathF.Round); // returns 2f
    
var result = (value: 1.75f, min: 0f, max: 1f)
    // this is equivalent to Math.Clamp(value: 1.75f, min: 0f, max: 1f)
    .Pipe3(Math.Clamp); // returns 1f 

CurriedPipes

Curried functions are also supported


Func<float, Func<float, Func<float, float>>> Clamp;

6f
    .Pipe(Clamp)(0)(5)
    .Pipe(x => Console.WriteLine($"clamp: {x}")); // prints 5 to the console

Thanks to Curryfy, none curried functions may also be passed

Func<float, float, float, float> Clamp = Math.Clamp;

6f
    .Pipe(Clamp)(0)(5)
    .Pipe(x => Console.WriteLine($"clamp: {x}")); // prints 5 to the console

In these cases the function will be curried as part of the pipe.

It is important to note that due to implicit casting limitations, methods cannot be passed implicitly. you will have to do one of the following:

//explicitly cast
6f
    .Pipe((Func<float, float, float, float>)Math.Clamp)(0)(5)
    .Pipe(x => Console.WriteLine($"clamp: {x}"));
  
//convert the method to a function
Func<float, float, float, float> Clamp = Math.Clamp;

Dependencies

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0 288 4/24/2021