oracle-samples/clara-rules

Create linked list implementation that returns views invalidated by mutation

Opened this issue · 2 comments

In Clara's memory after the changes in #184 we return java.util.LinkedList objects to callers in the engine in numerous places; see here for an example. Note that the value may be a LinkedList, but may also be a Clojure persistent data structure if we haven't performed multiple operations on the particular piece of data in the memory we're working with; see this case in add-elements! for an example. We rely on the caller performing any necessary work on the LinkedList returned, for example iteration, before the memory modified the underlying mutable data structure. This is not entirely unworkable since this an internal-only API, but it could lead to subtle, hard-to-detect bugs. For an example of such a problem see #303 ; this arose from a similar issue and the root cause likely causes issues with mutation as discussed there.

Unfortunately, our performance needs make it difficult to use Clojure's persistent data structures. However, it would be helpful for incorrect use of these mutable data structures to throw an exception rather than silently produce incorrect outputs. I'm envisioning creating a data structure that:

  • Is backed by java.util.LinkedList; we shouldn't reinvent the wheel there unless we need to.
  • Returns views of the underlying LinkedList.
  • Upon mutation, invalidates any views. Any attempt to access those views, or Iterator objects derived from them, would throw an exception.

Thinking about this some, I think it is reasonable to just "invalidate" old views - which really means (prolonged) lazy evaluation isn't "allowed" in most cases.

However, I am wanting to consider a case where say we actually were to allow lazy evaluation.
Could that semantically make any sense?

e.g.
Hypothetically, if there was a lazy seq over get-elements and it was realized at a later time after more mutations to the underlying elements in memory have happened, what is the “right” thing for it to do?

If there is a “right” or “obvious” thing it should do, perhaps this proposed data structure could potentially be designed to fit the case, as opposed to throwing an error for using lazy evaluation.


For now this is just an open-ended thought-exercise.
I'll try to think about it more, but posting it here to see what you (Will) or anyone else thinks.

Cross-post: @mrrodriguez had thoughts related to this sort of error-checking (though in a different way than described here) at #303 (comment).