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.Blob
is 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
Buffer
andBlob
types. ABlob
is immutable, much like Lovr's, while aBuffer
is mutable. It's possible to createBlob
s fromBuffer
s, and vice-versa.Apple's Foundation framework has
NSMutableData
andNSData
. This setup is a little clever:NSMutableData
is a subclass ofNSData
, so you can passNSMutableData
to 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 implementcopy
andmutableCopy
methods. Both classes implementmutableCopy
by returning a newNSMutableData
. But they diverge for implementingcopy
:NSMutableData
creates a newNSData
, butNSData
implementscopy
by merely returningself
. SinceNSData
is immutable, this is safe, because—memory management considerations aside—a copy of anNSData
would be semantically identical. APIs that take anNSData
, then, follow a simple pattern: always callcopy
on the incoming instance; if you got anNSData
, it's effectively a no-op, while anNSMutableData
will give you an actual newNSData
copy.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 aBlob
after callingfreeze
. Callingfreeze
on a frozen instance does nothing, allowing it to be called repeatedly. APIs, by convention, would generally immediately callfreeze
on anyBlob
instances they receive, unless they explicitly are intended to handle mutableBlob
s. Programmers would be expected to understand that theirBlob
s will freeze if not already frozen after calling most APIs. Or, there could also be aBlob:asFrozen()
method, which returnsself
if 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