Dynamic languages don't need protocols. If you want to make an existing object "conform to AsyncDisposable", you:
function DisposablImageBitmap(bitmap) {
bitmap[Symbol.dispose] ??= () => bitmap.close()
return bitmap
}
using bitmap = DisposableObserver(createImageBitmap(image))
Or if you want to ensure
all ImageBitmap conform to Disposable:
ImageBitmap.prototype[Symbol.dispose] = function() { this.close() }
But this does leak the "trait conformance" globally; it's unsafe because we don't know if some other code wants
their implementation of dispose injected to this class, if we're fighting, if some key iteration is going to get confused, etc...
How would a protocol work here? To say something like "oh in this file or scope, `ImageBitmap.prototype[Symbol.dispose]` should be value `x` - but it should be the usual `undefined` outside this scope"?