Can you figure it out? Functional caching
Okay, here is a challenge, without running the code, what do you think should be the result of this program, and why?
public class Program { private static void Main(string[] args) { Fetch<int> method = Get; method = AddCaching(method); method(); method(); method(); } public static int Get() { Console.WriteLine("Called"); return 1; } public delegate T Fetch<T>(); public static Fetch<T> AddCaching<T>(Fetch<T> fetch) { T cachedObject = default(T); bool isCached = false; return delegate { if (isCached == false) { cachedObject = fetch(); isCached = true; } return cachedObject; }; } }
Comments
The output probably should be "Called" (once)... but shouldn't "cachedObject" and "isCached" also be declared as static in order to do this? Or are the non-static references mixed into the delegate when it is created?
I'd like to check it out, but I'm in holidays at the sea and have no Visual Studio at hands... (weeps) :D
Lorenz,
No, they should not be declared static.
Note that they are local variables to the method, and so cannot be declared static (no such concept in the CLR).
I also think caching should work in this case. If I'm not mistaken, locals who are referenced in an anonymous delegate get "captured" in the generated class, so you can still reference them outside the method that declared them. This should work.
Avish,
100% correct. That is one of the few things in C# that behave like Boo (take a look at the compiler generated code once, it is interesting).
Thanks for your answer: really cool.
I'm learning a lot just by reading your blog, keep it up. ;)
Ayende,
Regarding your comment on static local method variables, ... "no such concept in the CLR". I believe this is limited by the C# compiler and not by the CLR. VB has the concept of static variables at the method scope.
ie.
Private Function NextNumber() As Integer
Static counter As Integer
counter += 1
return counter
End Function
Kim,
Wow, I had no idea.
Thanks for letting me know
Is this static per instance or static static?
Static per instance
Sorry if this is obvious, but isn't the delegate created there usually called a closure?
yes, that is a common name.
Ayende: I think you're still right about the CLR not having the concept of a "method local" static. The VB compiler just spits out an instance member or a static member depending on whether the declaring method is an instance method or a static method.
In other words, as far as the CLR is concerned it's exactly the same as a C# program which explicitly declares a static/instance variable. It's up to the language to make it a variable name that can't be referenced elsewhere.
Personally I don't have much use for this feature for "static" local variables, but I would like it for properties - like automatic properties in C# 3 (where the backing field is invisible from code) but this time where you could declare the variable for just the property, eg:
public string Foo
{
}
That would prevent other members within the same class from using the variable, forcing everything through the property - but still allowing me to put logic in the property (which you can't do with automatic properties in C# 3).
Jon
To answer the original question:
The "Result" of the program is "Called" being written to the console only once.
:)
I actually wrote similar memoization methods recently. I'm not sure why, but mine is not nearly as elegant.
Ayende, you probably already know this, but the correct term for such an algorithm is memoization, see http://en.wikipedia.org/wiki/Memoize
Wes Dyer (C# language team) has written a memoization function in C# 3:
public static Func<R> Memoize<R>(this Func<R> f)
{
R value = default(R);
bool hasValue = false;
return () =>
}
Comment preview