Prevent changes from the view, thus it can be passed around safely
Froze ArrayBuffer itself
Makes all views read-only.
Does anyone interested?
With a frozen ArrayBuffer, the engine can structured-clone them to another realm by sharing the memory directly instead of full copy.
I'd like to see the second option. It's important to have really immutable structures for cryptography to store private and public keys, curves params, initialization values, etc.
I think it should be two separate proposals with links to each other. Due to existing ability to implement read-only views with Proxy object, what makes one part of proposal some kind of controversial. Also it might take more time to implement and develop two proposals which have in common just a concept of read-only behavior and too much in differ.
Yes your example prevents the modification but it makes the object no longer a Uint8Array. Thus it will not pass the brand check, e.g. if some Web API needs a real Uint8Array.
Yeah, you're right about WebAPI. It seems like there would be dozens of issues with this.
I think there should be some more general solution like Object.freezeIndices, or an option to Object.freeze method to freeze only indices. Actually this is what strings do now, they can receive and change own properties but not indices. It would solve the problem in pretty straightforward way:
const buffer = new ArrayBuffer(8);
const view = new Uint8Array(buffer);
Object.freezeIndices(view); // Make Uint8Array instance read only.
Object.freezeIndices(buffer); // Make ArrayBuffer instance read only.
// or
Object.freeze(view, {indices: true}); // Make Uint8Array instance read only.
Object.freeze(buffer, {indices: true}); // Make ArrayBuffer instance read only.
As a side effect it should work for regular arrays and any other array-like objects too.
Now I got what you want. I think it might be achievable with some wrapper over ArrayBuffer to make it interoperable and do what you expect:
let buffer = new ArrayBuffer(1)
let view = new Uint8Array(new ArrayBufferWrapper(buffer))
new Uint8Array(view.buffer) // 👍 Now it's fine
* ArrayBufferWrapper – is example name and should be changed to something more suitable.
Actually you already use such wrapper but under the hood and without clear design of how it should be implemented. In the case of wrapper it's easier to use it without some magic, also it could be brand-checked in JavaScript and type-checked in TypeScript, if API requires such buffer to be identified as writable or readonly. And it looks more straightforward to JS design itself. Also It seems like it solves both of raised problems: it allows construct read-only views and implement immutable buffers behavior, like this:
function makeImmutableBuffer(source) {
return new ArrayBufferWrapper(Uint8Array.from(source).buffer); // Now there is no access to mutable buffer
}
IMO option {readonly: true} makes typed arrays interface inconsistent and complex. This option would be redundant in case of number as the first argument and it's not clear what to do in the case when it presented: ignore it or throw an error.
But it means any function in JS couldn't increase its arity and almost any enhancement is breaking. And I couldn't agree on that. No one should pass wrong number of arguments into a function and expect it to work properly.