The conception, birth, and first steps of an application named Charlie

Subscribe: Atom or RSS

The Cache is a Shadow, Not a Box

by Alister Jones (SomeNewKid)

Ahhh, the trials of being a self-taught developer. Just when you think you’re getting a handle on things, you receive fresh evidence that you don’t know jack. One week ago I saw Beginning Programming for Dummies in my city’s technical bookshop, and I allowed myself a wry smile, thinking, “I’m way beyond that.” Today, I plan to go into the city and buy that book. In the last week I have discovered that I really don’t understand the fundamentals of programming.

I have long known that application optimisation should be a final polishing step, not an initial design step. For that reason, my Entity System for Charlie included a few basic caching features, but I had disabled them. The plan was to enable the caching after the rest of Charlie had been developed, as part of a general optimisation phase. However, I brought forward the caching phase, as I wanted to make use of the custom cache code from Paul Wilson’s WebPortal project.

So I enabled the existing caching features of the Entity System and—snap!—the security stopped working. I could not figure out why. Worse, I sent myself off on a wild goose chase. My debugging efforts suggested that the problem was how my business objects were being populated. (If populated from the database, they worked. If populated from the cache, they did not work.) But I could not figure out where I had gone wrong.

Last night I was tossing and turning in my bed, worrying about Charlie. I’d like to say that a supermodel elbowed me in the side and told me to cut it out. But that had been the night before. Last night it suddenly occurred to me that perhaps I was misunderstanding the basics of the cache. Now this may seem so obvious that I should be ashamed of myself. However I had long been using the cache without problem, so it did not occur to me that I might have a gross misunderstanding of it. I mean, we stick an object into cache, and later get it out again. Who could get that wrong? Turns out, I was getting that wrong.

Let me tell you how I thought the cache worked. We’ll start by creating a simple ArrayList object. Here is the code, and a diagram illustrating how I viewed this object in my mind’s eye.

ArrayList original = new ArrayList();
original.Append("1");

Let’s put the object in cache. Again, here is the code, followed by a diagram illustrating how I envisaged the cache working.

Cache.Insert("original", original);

Clearly, I viewed the cache as being like a box into which we can place objects that we later want to retrieve. To show more clearly how I saw the box working, let’s add a few more items to the original object.

original.Append("2");
original.Append("3");

In my mind’s eye, I saw the cached object as being unaffected. Because that is how I saw the cache working, my belief was that if I retrieved the object from cache, it would be in the same state as it went into the cache.

ArrayList copy = Cache["original"] as ArrayList;

As I have suggested, I took it as a given that the cache worked like a box. When the object goes in, it remains unchanged until we take it out again. This seems so natural to me that it never occurred to me that the cache could work any other way. (But if I properly understood reference types, I might have realised my error. This is why I think I need to read Programming for Dummies after all.)

The belated insight I had last night was that the cache may not work like a box—that my basic assumption was wrong. I have just now created a test webpage in Charlie, and used its logging plugin to record what happens to an object placed in its cache. Here is what I discovered, starting again with the original ArrayList object.

ArrayList original = new ArrayList();
original.Append("1");

Again we put the original object in cache. This time, we envisage the cached object as being a shadow of the original object.

Cache.Insert("original", original);

If we see the cached copy as working like a shadow, and not like a box, we can properly predict what will happen if we then change the original object.

original.Append("2");
original.Append("3");

With this correct mental picture, we can also understand what happens when we retrieve the cached object.

ArrayList copy = Cache["original"] as ArrayList;

Because I had the wrong mental picture of the cache, I was using it improperly in the Entity System for Charlie. The subsequent problem to be solved is that the Entity System needs the cache to work like a box, not like a shadow. Fortunately, this is easy. If you don’t want the cached object to shadow the changes to the original object, you need to cache a clone of the original object. The clone will be unaffected by any changes to the original object.

ArrayList clone = original.Clone() as ArrayList;
Cache.Insert("clone", clone);

I cannot believe that I am the only person to have mistakenly viewed the cache as working like a box. If so, I hope this weblog entry may help others.

by Alister Jones | Next up: A Word on Lazy Loading

3 comments

______
Anonymous Anonymous said...  
 

I understand your confusion. But you should also know that taking an item out of the cache doesn't return a copy. It returns a reference to the original object. So its not a shadow, it is still a box. Only it doesn't store objects, it stores references to objects.

A common difference between languages that don't support classes inherently and those that do (like php4 and php5) is how they handle objects. In php4, it would do a memberwise copy of the object, sort of a incomplete clone. In php5, they changed it to copy the reference to the object only. This is why phpbb by default won't work in php5, because it was written to expect the old php4 behavior.

______
Anonymous Anonymous said...  
 

I wish this comment box lot you leave an e-mail address rather just a web page.

I was looking for a good explination of this basic language problem, and I belive a good one is at http://www.yoda.arachsys.com/ csharp/parameters.html.

If you want to contact me, you can at my name seperated by a period (i.e first.last) at sungardhe.com.

______
Blogger Alister said...  
 

Hi Jason.

Thank you for your comment about the cache returning a reference, not a copy.

It is a pity that I did not see your comment earlier. I updated my code to clone any Entity placed *in* the Cache, but I did not update the code to clone any Entity that comes *out* of the Cache. This mistake played havoc with Charlie. Fortunately, I ultimately realised my error, and now the caching is working perfectly. Phew!

And that was quite a good tutorial to which you linked. Thank you.

Post a Comment

----