Mutable Blobs #845
Replies: 5 comments 2 replies
-
|
Blobs are actually mutable, There are probably some other areas that wouldn't work properly if their blobs were modified though. Like, you might be able to crash the framework if you modified a ModelData/Rasterizer blob in just the right way. Also, love2d has a design similar to NSMutableData: They have So, I don't think right now there is a hard rule that Blobs must be immutable, and there could probably be Tangentially, another thing I've thought about is trying to bring the Buffer format code into Blob/lovr.data somehow. That way you could use the same system to write to both GPU data in buffers and CPU data in Blobs. |
Beta Was this translation helpful? Give feedback.
-
|
Here is a quick branch that implements Blob setters |
Beta Was this translation helpful? Give feedback.
-
|
Oh, I didn't realize the pointer was mutable all along. If it's already technically mutable, I suppose it wouldn't be a material change to just add the setter APIs. Yeah, the benefit of immutable types is just knowing that once you receive one, you know its contents will never change. You can hold onto it for a long time, and any invariants established in the first inspection will always hold true. Multiple threads can share references to the same object and read from it without locks at the same time and know that nobody will be changing it out from under them. Without immutable types, it's just up to the users to make sure they never mutate a value if another party is expecting it not to change.
Ooooh, that would be fantastic. Having a format description would let you write an entire table as binary data in one shot, fewer hoops to jump through.
For what it's worth, I did a code review on this commit and it looks good to me! Admittedly, it took a bit for me to do the review, because I've only touched Lua's C API a little and I had to learn exactly what some of the functions did. But still! It looks like it does what it's supposed to, and they're exactly the methods I would like to have. |
Beta Was this translation helpful? Give feedback.
-
Random idea: "structs" that combine blobs and buffer formats. You create a Struct by giving it a Blob and a format, then it uses metatable magic to expose dynamic properties that just read from or write to the blob according to the format. It would be an error to attempt to dynamically add additional properties, or assign a value having the incorrect type to a property. But the tradeoff is that it gives you memory layout guarantees, they may be more cache friendly, and you can readily submit a Struct to the GPU or write it out to disk. In many ways it's like userdata-backed APIs, except allowing format to be dictated from LUA code. |
Beta Was this translation helpful? Give feedback.
-
|
I merged the blob-setters branch, so now those |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
For writing to binary files or network protocols, it would be nice to have a mutable version of
Blob, with APIs likesetU16,setF32, etc.Blobis currently an immutable type. There are significant advantages to immutable types: they are easy to reason about, and are thread safe. However, those traits bring a wrinkle: I'm sure plenty of Lovr code assumes and relies upon the immutability ofBlob, so mutability APIs cannot simply be bolted onto the existing type without risking copious bugs.Node.js has
BufferandBlobtypes. ABlobis immutable, much like Lovr's, while aBufferis mutable. It's possible to createBlobs fromBuffers, and vice-versa.Apple's Foundation framework has
NSMutableDataandNSData. This setup is a little clever:NSMutableDatais a subclass ofNSData, so you can passNSMutableDatato any API that expects anNSData, but not the other way around. This introduces the risk of data being unexpectedly mutated while being held by something that expects it to be immutable. To address this, both classes implementcopyandmutableCopymethods. Both classes implementmutableCopyby returning a newNSMutableData. But they diverge for implementingcopy:NSMutableDatacreates a newNSData, butNSDataimplementscopyby merely returningself. SinceNSDatais immutable, this is safe, because—memory management considerations aside—a copy of anNSDatawould be semantically identical. APIs that take anNSData, then, follow a simple pattern: always callcopyon the incoming instance; if you got anNSData, it's effectively a no-op, while anNSMutableDatawill give you an actual newNSDatacopy.Another option could be to add mutable APIs to
Blob, but also introduce aBlob:freeze()method, wherein it would be an error to call a mutable API on aBlobafter callingfreeze. Callingfreezeon a frozen instance does nothing, allowing it to be called repeatedly. APIs, by convention, would generally immediately callfreezeon anyBlobinstances they receive, unless they explicitly are intended to handle mutableBlobs. Programmers would be expected to understand that theirBlobs will freeze if not already frozen after calling most APIs. Or, there could also be aBlob:asFrozen()method, which returnsselfif the instance is already frozen, or, if not, creates a newBlob, freezes it, and returns that.Beta Was this translation helpful? Give feedback.
All reactions