usethesource / capsule

The Capsule Hash Trie Collections Library
BSD 2-Clause "Simplified" License
404 stars 27 forks source link

Simplifies and enhances the use of writeCapabilityToken/mutator. #33

Closed wrandelshofer closed 2 years ago

wrandelshofer commented 2 years ago

Hello,

I am integrating the capsule collections into JHotDraw 8. I made a change, which may be of interest to you: I have simplified/enhanced the use of the writeCapabilityToken/mutator in capsule

With best regards, Werner

msteindorfer commented 2 years ago

Werner, thanks for getting in touch and for proposing the current PR.

Origins of Transient Concept

You have mentioned that the transients would remain writable after freezing. However, as the interface name Transient implies, it is meant to be an ephemeral short-lived representation for improving the performance of batched mutations.

The current design in Capsule follows Clojure's concept of transient collections, see summary, including the invariant "Can’t use after returning a persistent version".

Thus, the proposed PR would deviate from the current semantics and design of the transient collections.

Performance Considerations

Note that rotating the write capability token in freeze() would as well reset potential performance benefits, since it would be equivalent (in terms of performance) to starting with asTransient() fresh again.

Your Use Case

It appears that you want to use mutable collections by default and create immutable snapshots (by rotating the token and keeping the transient instance alive). Is that correct? Could you elaborate on your use case?

wrandelshofer commented 2 years ago

Thank you for your reply. πŸ˜€

My Use Case I have the following use case:

Right now, we have solved this by

This is inefficient due to the frequent cloning, and - in case of 1.b) the application may crash with an UnsupportedOperationException.

I have lots of existing functions (millions of lines). It is easy to refactor setter/getter accesses to business objects, but it is costly to refactor usages of mutable collections everywhere in the code.

I have experimented with interfaces for immutable collections. This solves problems caused by 1.b) but is still inefficient because of the frequent cloning from/to mutable collections.

So, I am now experimenting with persistent collections, that can be efficiently converted from/to mutable collections:

Performance Considerations Yes, I am aware that the proposed freeze() creates a new mutator object, and thus resets potential performance benefits. It is equivalent to calling c=c.freeze().asTransient(). The difference is, that the transient collection does not throw IllegalStateException after a freeze().

This way, I can easily change code in my large code base from businessObject.set(mutableCollection.clone()); to businessObject.set(mutableCollection.freeze()). - The existing code may have references to mutableCollection elsewhere, and may mutate that collection again.

wrandelshofer commented 2 years ago

Therefore I had a misconception about the terminology of 'transient' and 'freeze'. I thought 'transient' was the mutable counterpart of 'persistent'.

My proposed code would have turned the transient collections into mutable collections, and thus would be a design change and not just a 'fix' as I had presumed.

Thank you for bringing that to my attention! πŸ˜€ I am closing the pull request.😊