Java Vs C# Closures

Performance:
Closure:  0.816 sec
Interface: 0.258 sec
Inline(PureC#): 0.22 sec

Conclusion: Never use Actions, Funcs, Lambdas, Delegates and all the garbage c# brought, switch to plain old interfaces like java does.

Lets say we have a utility method to read from a dictionary

public static V GetOrInsert<K, V>(Dictionary<K, V> dict, K key, Func<T> createNewValue)
        {
            V value;
            if (dict.TryGetValue(key, out value)) return value;
            value = createNewValue();
            dict[key] = value;
            return value;
        }

Now we try to use it:

[ContextMenu("GetOrInsertClosure")] public void GetOrInsertClosure()
{
    new Benchmark().Test(() =>
    {
        int sum = 0;
        Dictionary<int, int> a = new Dictionary<int, int>();
        for (int i = Runs; i-- > 0;)
        {
            sum += GetOrInsert(a, i, ()=>MyClassField);
        }
    });
}

Woops !!! Notice: ()=>MyClassField. This introduced closure, an evil bug that slows code by x4. The same would have happened if we used an instance method.

In C# when a lamba expression that requires “this”, for example : ()=>this.MyClassField
or when it uses an instance method eg this.MyClassMethod then a closure forms. This decreases performance and generates garbage. Therefore c# sucks.

More Details: https://blog.jetbrains.com/dotnet/2014/07/24/unusual-ways-of-boosting-up-app-performance-lambdas-and-linqs/

Why this bug happens ? Because c# closures can read Mutable variables (even if the value changes, it will refer to its latest value). Wanna see something crazy ?

Action recursion = null;
recursion = () =>
{
    ++Calls;
    if (Calls < 100)
    {
        recursion(); //totally allowed. it is not null
    }
};

So c# implementation of closure, constructs an outer class that has references to the class and scope . That’s totally inefficient. Constructing a “new” instance per call. This forces you to ban lamba expresses entirely. And instead use manually constructed closures by hand as if you were in the dinosaur era.

Therefore java is better, because not only is it faster, but it automatically constructs “final” optimized closures for you, and doesnt force you to rewrite them manually by hand like c# does.
More Details: http://vineelkumarreddy.com/2016/01/19/the-rationale-behind-java-lambda-closures/

Here is the workaround to construct efficient closures like Java:

public static V GetOrInsert<K, V>(Dictionary<K, V> dict, K key, ICreator creator)
    {
        V value;
        if (dict.TryGetValue(key, out value)) return value;
        value = creator.Create();
        dict[key] = value;
        return value;
    }
}

public interface ICreator
{
    T Create();
}

And use it like :

public class TestDictionaryExtensions : MonoBehaviour, ICreator
{
    public int MyClassField = 1;

    public int Create()
    {
        return MyClassField;
    }

[ContextMenu("GetOrInsertInterface")] public void GetOrInsertInterface()
{
    new Benchmark().Test(() =>
    {
        int sum = 0;
        Dictionary<int, int> a = new Dictionary<int, int>();
        for (int i = Runs; i-- > 0;)
        {
            sum += GetOrInsert(a, i, this);
        }
    });
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s