patterncsharpMinor
Calculation caching experiment
Viewed 0 times
experimentcachingcalculation
Problem
There are a lot of numerical properties to be invoked many times with an expensive calculation. Let’s say for the sake of example, they expose a Factorial:
I was looking for a way to cache them while keeping syntax clean, so property calculation logic will not intermix with caching. A proposed solution is:
Where library code is:
And:
public class Analysis
{
public double n10 => F(10);
public double n100 => F(100);
double F(int n) =>
n <= 1 ? 1 : n * F(n-1);
}I was looking for a way to cache them while keeping syntax clean, so property calculation logic will not intermix with caching. A proposed solution is:
public class Analysis
{
public double n10 => this.Cached() || F(10);
public double n100 => this.Cached() || F(100);
double F(int n) =>
n <= 1 ? 1 : n * F(n-1);
}Where library code is:
public static class Caching
{
static ConditionalWeakTable> Values { get; } =
new ConditionalWeakTable>();
public static Value Cached(this object target, [CallerMemberName] string name = null) =>
Values.GetOrCreateValue(target).ContainsKey(name) ?
new Value(() => Values.GetOrCreateValue(target)[name], null) :
new Value(null, v => Values.GetOrCreateValue(target)[name] = v);
}And:
public class Value
{
public static implicit operator Value(double value) => new Value(() => value, null);
public static implicit operator double(Value value) => value.Getter();
public static bool operator true(Value value) => value.Getter != null;
public static bool operator false(Value value) => value.Getter == null;
public static Value operator |(Value cached, Value computed)
{
cached.Setter(computed);
return computed;
}
public Value(Func getter, Action setter)
{
Getter = getter;
Setter = setter;
}
Func Getter { get; }
Action Setter { get; }
}Solution
Operator-free version (answer to...your answer):
Do not look at marginal style differences (I cannot get used/appreciate expression bodied functions but it's just my own problem), point I'd like to highlight is:
Few minor notes about current code:
I understand your point of view (C# syntax isn't so clean to be used for business logic) but instead of forcing syntax and change operators semantic I'd prefer to use another language. Boo was first that came to my mind (especially because to change and extend the language to have a DSL is incredibly easy). I used it few years ago then I'm not up-to-date with its evolution. There are also other tools (second thought if for Microsoft Modeling SDK if you like visual editors instead of plain text code)
public static class Analysis
{
public static readonly Lazy n10 = new Lazy(() => F(10));
private double static F(int n)
{
return n <= 1 ? 1 : n * F(n - 1);
}
}Do not look at marginal style differences (I cannot get used/appreciate expression bodied functions but it's just my own problem), point I'd like to highlight is:
- You do not need
Onceclass, Framework already has a class for lazy creation of values:Lazy. It even nicely handle thread-safety issues (safe creation and/or publication) if field is not static (in that case C# itself helps us.)
Few minor notes about current code:
Analysisclass has no need to be instantiable and all methods can bestatic.
- Class itself can then be
static.
- IMO you do not need a dictionary, first of all because of the performance impact (even if it's a concurrent collection without locks) but also because it limits its usage to static methods (you use
MethodInfoas key).
I understand your point of view (C# syntax isn't so clean to be used for business logic) but instead of forcing syntax and change operators semantic I'd prefer to use another language. Boo was first that came to my mind (especially because to change and extend the language to have a DSL is incredibly easy). I used it few years ago then I'm not up-to-date with its evolution. There are also other tools (second thought if for Microsoft Modeling SDK if you like visual editors instead of plain text code)
Code Snippets
public static class Analysis
{
public static readonly Lazy<double> n10 = new Lazy<double>(() => F(10));
private double static F(int n)
{
return n <= 1 ? 1 : n * F(n - 1);
}
}Context
StackExchange Code Review Q#141756, answer score: 4
Revisions (0)
No revisions yet.