The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

Mark Elston (133) [Avatar] Offline
#1
At the start of section 2.3.2 you say: "But, it does not enforce the function initializer func(a) from being executed multiple times for the same value, while evaluating the expression."

I don't understand this. The initializer function is only called if the value is not found in the cache, right? So why would it ever be called multiple times for the same value?
Riccardo Terrell (31) [Avatar] Offline
#2
Thanks for the question.
In the example that you are pointing out, the Memoization function is implemented using a ConcurrentDictionary as form of defense against possible race-condition.

public static Func<a, b> Memoize<a, b>(this Func<a, b> func)
{
    var cache = new ConcurrentDictionary<a, b>();
    return a => cache.GetOrAdd(a, func);
};


However, according with the Microsoft documentation, the method GetOrAdd does not prevent the function `func` from being called more than once for the same given argument, but it does guarantee that the result of only one “evaluation of the function” is actually added to the collection. For example, there could be multiple threads checking the cache concurrently before the cached value is actually added.
Moreover, there is no way to enforce the function `func(a)` to be thread-safe, in fact, without this guarantee, it is possible that in a multithreaded environment, multiple threads could access the same function simultaneously. Ergo, the ` func(a) ` should also be thread-safe itself. The solution proposed, avoiding primitive locks, is to use the Lazy<T> construct in .NET 4.0. This solution gives you both the guarantee of full thread safety, regardless the implementation of the function `func`, and ensures a single evaluation of the function.

public static Func<a, b> Memoize<a, b>(this Func<a, b> func)
{
    var cache = new ConcurrentDictionary<a, b>();
    return a => cache.GetOrAdd(a, new Lazy<a>(() => func(a), LazyExecutionMode.EnsureSingleThreadSafeExecution)).Value;
};


please let me know if this is clear, I will put a note to add further explanation in the section.
Mark Elston (133) [Avatar] Offline
#3
Thanks. I think that explains it pretty well.
Riccardo Terrell (31) [Avatar] Offline
#4
Cool!! I will reformulate and update the chapter to make it more clear.
Thanks for the feedback... and keep going smilie