Add support for immutable xvm structures - #565
Conversation
|
This is a building block I want, and some of it is more careful than it looks — One question decides most of my comments, and I'd rather ask than assume: can a structure be frozen after it has been shared, or is the rule "build, freeze, then publish"? If it's build-freeze-publish, then Worth flagging either way: #549 is open and argues The larger thing, not blocking: this makes immutability advisory — a runtime check every current and future mutator has to remember, with no way to say "I require an immutable structure" in a signature. That's fine as a first step, but it's worth deciding now whether the destination is structural (a distinct immutable type, or freeze-by-construction returning a new instance with |
lagergren
left a comment
There was a problem hiding this comment.
Line-level notes to go with my summary comment above. The first one is the only one I'd call blocking; the rest are readability and contract questions.
Ideally, when we load from disk (or from byte[] or whatever), we will either get a read-only form, or we will need to say "instantiate this thing in a mutable form" or "instantiate this thing in a read-only form". When we create one from scratch (e.g. a compiler), it is a mutable form. Obviously. From a mutable form, it can be transitioned to a read-only form. From a read-only form, it must be copied to obtain a mutable form. When mutable, the data model is not intended to be (nor is in any way) thread safe. Trying to use it in a multi-threaded manner when it is mutable is a fool's errand. Don't do that. When read-only, the data model should be thread safe. I cannot (yet) warrant that it is, but it should be reasonably close outside of tests explicitly intended to show otherwise. Again, the intention is simple: single threaded if mutable, and only after explicitly made immutable should any thread even get to look at the structure.
Something like this. I'm trying to retrofit this on top of an "organically evolved" data structure. It's not going to immediately come out as perfect.
Sure. But note that it does nothing to something that is already read-only. So the model is consistent.
Actually, that issue is one of the reasons that I did this project and did it now. The idea of "written by one thread and read by others" is obviously incompatible with what I've described above.
Correct. This is Java, so we're largely out of luck in this regard anyhow. The point is: As we utilize the read-only option, e.g. by default on loading, tools that need a mutable form will need to explicitly ask for a mutable form, or they'll blow up. I'm ok with that as a short term problem to fix. And when we do fix it, it should eliminate some of the bleed-through issues that either already do happen or that we fear could happen. |
This is the contract I wanted, and I guess I am just looking for ways that the code clearly enforces it, so that I cannot accidentally not do this. But as I've said all the time - this is fine in the current environment and merge it as is. Would be cool to show you how a "replaced representation" example will "work" now e.g. Lists instead of Arrays in ways it didn't "work" before. And some unit tests that exercise the API would be nice mainly as documentation. |
BTW - There are ways to do som of this in Java. I would define a trivial wrapper FrozenArray, which will, in all situations be absolutely as performant as a raw array, but with none of the mutability and Object:s. |
This is the next chunk of work to help support bundles, efficient caching, etc. It's not a fix to anything in and of itself, but a building block that we need. As an aside, there are going to now be opportunities to efficiently replace things like array based APIs with e.g. List, now that we have mutable vs immutable in the structures.