Question

This question basically expands on this question where the answer is that the single argument pipeline operator |> is compiled to the same CIL as the unpiped version. But what about ||> and |||>? MSDN suggests that real tuples are used to wrap the arguments.

But do ||> and |||> really allocate a .NET Tuple to wrap the arguments and then unwrap them again just pass them to a function or is the compiler optimized to handle these operators by just rewriting the CIL like it does with |>?

Update:

Thank you for the answers. It depends on whether the --optimize+ parameter is passed to the F# compiler.

Default release builds in with F# 3.1 in Visual Studio 2013 don't create tuples. Default debug builds do create tuples.

Was it helpful?

Solution 2

Yes, where possible, the compiler will optimize away the operators just like it does with |>.

Just as a fun example, the compiler will optimize this code

let add a b = a + b
let test() = (1,2) ||> add

to this

3

And even if you parameterised test

let test t = t ||> add

it would compile to this C# equivalent

int test(int x, int y) { return x + y; }

In real, more complex code, you might not see such extreme optimizations but it gives you an idea of what the compiler can do.

OTHER TIPS

EDIT: Originally I actually confused the optimized and non-optimized assemblies when trying out, and thought it didn't optimize it out; but it actually does.

I actually tried it out. I tried the following module:

module Library1

let f x y = (x, y) ||> (+)

And then decompiling it with ILSpy.

When compiling without optimizations (--optimize-), it gives the following:

public static int f(int x, int y)
{
    Tuple<int, int> tuple = new Tuple<int, int>(x, y);
    int item = tuple.Item1;
    int item2 = tuple.Item2;
    return item + item2;
}

When compiling with optimizations (--optimize+), it gives the following:

public static int f(int x, int y)
{
    return x + y;
}

So yes, the optimizations do remove the tuple creation.

Most of the F# operators are declared as inline, which means that they essentially work by text replacement before the optimizer even comes into play. For reference, here is the definition of ||> from the source code

let inline (||>) (x1,x2) f = f x1 x2

If you compare this to |> which is

let inline (|>) a b = b a

I would expect similar optimisations

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top