What do people think of cachedWithin="instance" along the lines of cachedWithin="request"

thinking about this primarily for functions <cffunction> :: Lucee Documentation

you create a object/cfc (which you may stick in the application scope), that’s the instance

application.myCacheThing = new com.zac.something.obj();
// obj.cfc
component {
  function doExpensiveFetch( id )  cachedWithin="instance"  {
    // do some heavy lifting, slow requests etc
    return result;
  }
}

the cache lasts for the lifetime of the object

within the object you have the following ways to clear the cache programatically, or you just recreate the object

instanceCacheClear(myfunction) //specfic
instanceCacheClear() //entire instance
// obj.cfc
component {
  function doExpensiveFetch( id  cachedWithin="instance"  {
    // do some heavy lifting, slow requests etc
    return result;
  }
  function purge(){
    instanceCacheClear();
  }

}

not tied to it being named instance, could be object, happy to discuss…

solves [LDEV-1348] - Lucee

conversation started on cfml slack Slack

4 Likes

It’s an interesting idea. Most (like 99.99%) of my CFCs are cached in the application scope; so there’s no functional difference between the “instance” and the “component” for me. I didn’t even realize that the Function cache wasn’t instance specific - that’s good to know.

Two issues that sprang to mind here.

To me it seems to be a code-smell. It’s conflating “what the function does” with “how it’s being used”. It should be the calling code’s job to determine whether or not a result needs to be cached; not the signature of the function.

It’s also really easy to implement a decorator for a class if in one’s application one needs to implement caching around an object or a method, at the same time not being tied to how the Lucee developers decided to bake the caching in.

Equally… if the data is appropriate to be considered part of the object’s state (which is all you’re doing here really, innit?), one just needs to put the data into the variables scope of the object. Done. This follows standard and familiar OOP principles, rather than “Special Magic Lucee Way (tm)”.

here’s the er, very lengthy PR

previously the UDF source or full path was used, so it’s a bit more efficient

but simple approach that would make cache keys change between restarts… yeah not so useful

This initiative concerns the problem you mention: ( [LDEV-1348] - Lucee). The following line occurs in the description of that problem:

"As it is, both calls to test() results in the same information, because the state of the object is ignored."

I think that things are more complicated than that statement says. The complication arises from the fact that, in the tests mentioned, the definition of state is related to a this-scoped variable. Complications would be avoided if you used a variables-scoped variable instead.

In any case, I consider it poor design to give an instance the responsibility of caching the result of one or more of its methods. An implication is that an instance will automagically change behaviour after a period of time. That could be startling to the caller.

In addition, such caching assigns to an instance and its methods the extra responsibility of caching. In so doing it contravenes the Single-Responsibility principle.

According to this principle an instance or any of its methods should ideally specialize in doing one, and only one, thing. After they’ve done their thing, a caching specialist would then come in and cache the result.