I don't understand how we could deprecate a type that we are actively using and for which there is no replacement.
I don't want to do this for expressly the reason that you're mad about the current situation: ByteBuffer isn't (and shouldn't be) a general-purpose currency type. Pushing this out into its own repo anoints ByteBuffer as currency type by acclamation, and makes it much harder for the Swift ecosystem to land on an actual currency type by strangling the need for one.
ByteBuffer has one explicit purpose: parsing and serializing network protocols. It is designed with a substantial API surface to make doing that as easy as possible. This goal is totally unrelated to the "I have an unstructured bag of bytes" situation. If you evaluate ByteBuffer's API surface from the idea that all you want is to shuffle bytes around without parsing them, yeah, it seems weird.
A general purpose bag-of-bytes currency type is useful, and I'd like to see folks line up behind the need for that thing. That is a substantially more valuable thread of discussion.
Ok, with that out of the way, I'd like to separately address the later comments. But first: it would be really helpful if your first response to seeing a type whose API seems needlessly complex to you was not to assume that the authors of that type are idiots. It's perfectly reasonable to ask why ByteBuffer is the way it is, as @tera has just done very reasonably, and there are definitely parts of the API that want to be redesigned, but when you write
my assumption is that you don't know what you're talking about and haven't bothered to find out. This is a bit weird to me: I'm right here, answering questions on the Swift forums, all the time. If you wanted to know why ByteBuffer was the way it was, you could just ask, instead of writing the above comment. When I read that comment, I read that as you saying that you think ByteBuffer doesn't do a good job at its core goal. That's laughable: I use it every day to do what it was designed to do, and it's phenomenal at it.
Relatedly:
The fact that you pulled a documentation link out means you must presumably have opened that page, which says, in the very first paragraph:
It’s marked as very unsafe because it might contain uninitialised memory and it’s undefined behaviour to read it.
This distinguishes it from withUnsafeReadableBytes, which vends you initialized memory. Put another way, this code is fine: buffer.withUnsafeReadableBytes { $0.first }. This code is not: buffer.withVeryUnsafeMutableBytes { $0.first }. We are attempting to capture that distinction without writing the much less handy function name withUnsafePotentiallyUninitializedMutableBytes. Is the name bad? Sure. Is the function necessary? Yes, we use it often.
I agree. Those methods exist to resolve the fact that variadic generics do not exist, so we have no more concise way to express this operation. I'm open to suggestions for how we could do this differently.
ByteBuffer has three very distinct properties that are different than [UInt8], and only one of them cannot be implemented on top of [UInt8].
The first is a pair of cursors, a read and write cursor. This allows you to implicitly load a sequence of bytes from wherever you have read up to, without needing to drop them from the front. This behaviour is trivially implemented on top of [UInt8], and is in fact pretty close to ArraySlice<UInt8>, though unlike ArraySlice<UInt8> you can "rewind" a read by moving the cursor backwards.
The second, and much more important, behaviour is that ByteBuffer allows you to write to uninitialised memory. This has a number of powerful features. It makes appending to ByteBuffer extremely cheap, because we don't have to pre-initialise memory. It means that ByteBuffer semantically does have a capacity (Array's capacity is non-semantic), it allows temporarily "skipping" bytes and coming back to fill them in later, and it enables easy interop with C APIs without requiring expensive zeroing first.
The third, and final, behaviour is that ByteBuffer can grow using realloc. This is not something Array can do. The effect is that for large ByteBuffers, further growth can occur without needing to copy the existing bytes, because realloc can (sometimes) transparently attach a new page to the back of an existing one.
Finally, even if ByteBuffer did not have these differences, it would be a mistake to add these methods to [UInt8]. As @taylorswift observed, ByteBuffer has a large API surface for a specialised use-case. We should not burden all users of [UInt8] with this API surface.
What we'd like to do instead is to make it easy for users to pick the shape that fits them best. If you need to parse, it would be great if you could wrap a type into ByteBuffer without copying it. We can't do that today because ByteBuffer's API surface cannot be implemented on top of any other currency type in Swift. If we could, then @taylorswift's problem would be solved, because folks wouldn't need to express their API surface in terms of ByteBuffer in order to support zero-copy transformations to and from it.