Tutorial :Which languages have support for return value caching without boilerplate code?



Question:

For methods where ...

  • there exists a static one-to-one mapping between the input and the output, and
  • the cost of creating the output object is relatively high, and
  • the method is called repeatedly with the same input

... there is a need for caching result values.

In my code the following result value caching pattern is repeated a lot (pseudo-code in Java, but the question is language-agnostic):

private static Map<Input, Output> fooResultMap = new HashMap<Input, Output>();  public getFoo(Input input) {    if (fooResultMap.get(input) != null) {      return fooResultMap.get(input);    }    Output output = null;    // Some code to obtain the object since we don't have it in the cache.    fooResultMap.put(input, output);    return output;  }  

Repeating this structure all the time is a clear violation of the DRY principle.

Ideally, I'd like the code above to be reduced to the following:

@CacheResult  public getFoo(Input input) {    Output output = null;    // Some code to obtain the object since we don't have it in the cache.    return output;  }  

Where the theoretical CacheResult annotation would take care of the caching I'm currently doing by hand.

The general term for this type of caching is "memoization".

A good example of the exact functionality I'm looking for is Perl core module "Memoize".

In which languages does such a Memoize-like caching solution exist (either at the language level or the library level)? In particular - does such a solution exist for any major platform such as Java or .NET?


Solution:1

Not a language built-in, put the CPAN module Memoize is reasonably popular in Perl land, I think:

   # Compute Fibonacci numbers      sub fib {        my $n = shift;        return $n if $n < 2;        fib($n-1) + fib($n-2);      }        use Memoize;      memoize('fib');  


Solution:2

The Caching Handler - in .Net 'Enterprise Library'

http://msdn.microsoft.com/en-us/library/cc511757.aspx

[CachingCallHandler(0, 0, 30)]  public decimal GetSavingsBalance(int accountNumber)  {    // Code here to extract balance from database.    return balance;  }  


Solution:3

Python has a number of decorator recipes, e.g. the decorator module, that work for this (if the parameters are all immutable), and it has implementations on both the JVM and .NET.


Solution:4

The Spring's incubation area, springmodules has exactly this functionality for Java.

Springmodules cache is still at 0.8 release level, but it worked generally quite well when I tried it last year. There are options to configure the caching within spring configuration files as well as with annotations - which looks pretty much exactly like your example. From their docs:

public class TigerCacheableService implements CacheableService {      @Cacheable(modelId = "testCaching")    public final String getName(int index) {      // some implementation.    }  ...  }  

You can choose the back end implementation of the cache. When I was trying it I had good results hooking it up to ehcache which has nice spring integration too. You can declaratively set up ehcache to cache (in-memory and/or disk) the results of the methods that you tag with the @Cacheable annotation.


Solution:5

You could implement the @CacheResult annotation in Java, using for example ASM to transform the method to add the memoization code.


Solution:6

Microsoft T-SQL can cache the return values from a CLR function on a pr. query basis...

(No boilerplate except the correct attributes on the method when writing it in CLR.)


Solution:7

Not a direct answer to your question, but if you are maintaining many caches, it may be worthwhile to use OSCache (Java) for management of those caches. Eviction of stale objects etc, becomes a problem you don't have to worry about.

You would still have to use the basic pattern of "check cache", "return cached" or "create and add to cache" though.


Solution:8

It is possible to factor out code like that in Java, although Java's syntax remains verbose

private static final Cache<Input, Output> fooCache = Caches.newInstance(      new Factory<Input, Output>() { public Output create(Input input) {          return ... some code ...;      }}  );  public static Output getFoo(Input input) {      return fooCache.get(input);  }  

With better syntactical support for anonymous inner classes, that could become, say:

private static final Cache<Input, Output> fooCache =      (Input input) (... some code ...);  public static Output getFoo(Input input) {      return fooCache.get(input);  }  

This is one thing that AOP solution can do, at the expense of having to deal with a bit of magic.


Solution:9

This question/answer addresses Memoization in C#. It doesn't cache the results, but could be easily changed to make the map static with a ReaderWriterLock.

Here's a sample from the link given:

public static Func<A, R> Memoize<A, R>(this Func<A, R> f)  {    var map = new Dictionary<A, R>();    return a =>      {        R value;        if (map.TryGetValue(a, out value))          return value;        value = f(a);        map.Add(a, value);        return value;      };  }  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »