Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement caching in an immutable way?

I've read and heard a lot of good things about immutability, so I decided to try it out in one of my hobby projects. I declared all of my fields as readonly, and made all methods that would usually mutate an object to return a new, modified version.

It worked great until I ran into a situation where a method should, by external protocol, return a certain information about an object without modifying it, but at the same time could be optimized by modifying the internal structure. In particular, this happens with tree path compression in a union find algorithm.

When the user calls int find(int n), object appears unmodified to the outsider. It represents the same entity conceptually, but it's internal fields are mutated to optimize the running time.

How can I implement this in an immutable way?

like image 813
Max Yankov Avatar asked Nov 01 '22 05:11

Max Yankov


1 Answers

Short answer: you have to ensure the thread-safety by yourself.

The readonly keyword on a field gives you the insurance that the field cannot be modified after the object containing this field has been constructed. So the only write you can have for this field is contained in the constructor (or in the field initialization), and a read through a method call cannot occur before the object is constructed, hence the thread-safety of readonly.

If you want to implement caching, you break the assumption that only one write occurs (since "caching writes" can and will occur during you reads), and thus there can be threading problems in bad cases (think you're reading lines from a file, two threads can call the find method with the same parameter but read two different lines and therefore get different results). What you want to implement is observational immutability. This related question about memoization may help you with an elegant answer.

like image 159
dureuill Avatar answered Nov 09 '22 10:11

dureuill