Discussion on: What the heck is Currying anyway?

slavius profile image

Normal function in IL:

IL_0000: ldarg.0      // a
IL_0001: ldarg.1      // b
IL_0002: add
IL_0003: ldarg.2      // c
IL_0004: add
IL_0005: ldarg.3      // d
IL_0006: add
IL_0007: ret

// function call
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: ldc.i4.3
IL_0003: ldc.i4.4
IL_0004: call  int32 CurryDemo.BenchmarkNormalVsCurry::NormalAdd(int32, int32, int32, int32)

Curry function in IL:

IL_0000: newobj  instance void CurryDemo.BenchmarkNormalVsCurry/'<>c__DisplayClass1_0'::.ctor()
IL_0005: dup
IL_0006: ldarg.0      // a
IL_0007: stfld  int32 CurryDemo.BenchmarkNormalVsCurry/'<>c__DisplayClass1_0'::a

IL_000c: ldftn  instance class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, int32>> CurryDemo.BenchmarkNormalVsCurry/'<>c__DisplayClass1_0'::'<CurryAdd>b__0'(int32)
IL_0012: newobj  instance void class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, int32>>>::.ctor(object, native int)
IL_0017: ret

// function call
IL_0000: ldc.i4.1
IL_0001: call         class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, int32>>> CurryDemo.BenchmarkNormalVsCurry::CurryAdd(int32)
IL_0006: ldc.i4.2
IL_0007: callvirt     instance !1/*class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, int32>>*/ class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, int32>>>::Invoke(!0/*int32*/)
IL_000c: ldc.i4.3
IL_000d: callvirt     instance !1/*class [System.Runtime]System.Func`2<int32, int32>*/ class [System.Runtime]System.Func`2<int32, class [System.Runtime]System.Func`2<int32, int32>>::Invoke(!0/*int32*/)
IL_0012: ldc.i4.4
IL_0013: callvirt     instance !1/*int32*/ class [System.Runtime]System.Func`2<int32, int32>::Invoke(!0/*int32*/)


// * Summary *

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.450 (2004/?/20H1)
AMD Ryzen 7 3800X, 1 CPU, 16 logical and 8 physical cores
.NET Core SDK=3.1.401
  [Host]        : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT
  .NET Core 3.1 : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT

Job=.NET Core 3.1  Runtime=.NET Core 3.1

|        Method |       Mean |     Error |    StdDev |
|-------------- |-----------:|----------:|----------:|
| TestNormalAdd |  0.0203 ns | 0.0093 ns | 0.0083 ns |
|  TestCurryAdd | 33.1419 ns | 0.2941 ns | 0.2607 ns |

// * Hints *
  BenchmarkNormalVsCurry.TestNormalAdd: .NET Core 3.1 -> 1 outlier  was  removed (1.57 ns)
  BenchmarkNormalVsCurry.TestCurryAdd: .NET Core 3.1  -> 1 outlier  was  removed, 2 outliers were detected (33.77 ns, 35.37 ns)

// * Legends *
  Mean   : Arithmetic mean of all measurements
  Error  : Half of 99.9% confidence interval
  StdDev : Standard deviation of all measurements
  1 ns   : 1 Nanosecond (0.000000001 sec)

// ***** BenchmarkRunner: End *****

the program:

    class Program
        static void Main(string[] args)
            var summary = BenchmarkRunner.Run<BenchmarkNormalVsCurry>();

    public class BenchmarkNormalVsCurry
        public static int NormalAdd(int a, int b, int c, int d)
            return a + b + c + d;

        public static Func<int, Func<int, Func<int, int>>> CurryAdd(int a) =>
            (b) =>
                (c) =>
                    (d) => a + b + c + d;

        public void TestNormalAdd() => NormalAdd(1, 2, 3, 4);

        public void TestCurryAdd() => CurryAdd(1)(2)(3)(4);
xtofl profile image

Fantastic that you emphasize this. While FP code constructs unclutter the code, without proper tool support you just move the clutter into the runtime.

Indeed, JavaScript (nor C#) was never designed to go full throttle on functional programming concepts. Therefor the JIT compiler doesn't optimize any of it.

Languages like Haskell, F#, Erlang, Lisp, are built for this, and will handle it in a better way.

heytulsiprasad profile image
Tulsi Prasad Author

Thanks man, for putting this out here!

I'm definitely interested to know what happens behind all the functions and about compilation. However, I'm not quite experienced at it, but hopefully this will be helpful to others and even me in future.