Repository navigation
feat(base): Byte and Word16, with byte conversions for U32 (draft, for consideration) - #1660
ScottMoore0 wants to merge 1 commit into
Conversation
Byte{data: Word(8n)} and Word16{data: Word(16n)}, built as U32 is: wrapping
arithmetic and bit ops, comparisons, to_nat/to_u32/from_nat/show,
U32.to_byte and U32.to_word16 (the low bits), U32.byte, U32.of_bytes(_be),
Word16.of_bytes, and Word.lo/hi/cat to split and join words. One law:
U32.to_byte(Byte.to_u32(b)) == b.
Named Byte and Word16, not U8 and U16: 11 hub packages declare their own
U8 (3 also U16), and a redeclared Base name is refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, this is clean and well tested, and the naming survey against the hub is exactly the check we'd want. We're going to keep Byte out of Base for now. Base's byte APIs (File.read_bytes, TCP/UDP, args_bytes) all take and return U32, so a Byte type there would be a second representation that nothing in Base produces or consumes. Every check would pay for it (Base +8%, and 52 names reserved for every module under #1042) while most programs never touch it. Without natives it would also be too slow to be the I/O representation. We may add something like this in the future, but for now we're focused on keeping Base small and concise. Please do publish it as a hub package. That gives the packages rolling their own U8 one shared, proved byte type, and if byte I/O ever moves off U32 we'd design Byte in Base together with its natives and start from yours. |
The Bend team declined Byte and Word16 for Base (bendlang/bend#1660: Base's byte I/O is U32, and a second representation would cost every check) and asked for a hub package instead. This is that code (the author's commit 3d33c01, now MIT), as a package: every name carries the package prefix, since a package declaring Byte, Word.lo or U32.to_byte would break once Base adds them. Byte is ByteU8, Word16 ByteU16, U32.x ByteU32.x, Word.lo/hi/cat ByteBits.lo/hi/cat; one file per type, and bits.bend for the word splitting. It uses only Base's public types and defs. Laws, 12, all proved, --verdict included: the PR's law (a byte to a U32 and back) and its 16-bit twin, a U32 to a byte or 16-bit word and back being its low bits, a U32's bytes joining back to it and four bytes' bytes being themselves, the 16-bit join agreeing with the 32-bit one, addition commuting (Base's Word.add_comm), and the PR test's three proved vectors. ref/: 1904 cases against Python's integers. The README adds a note for packages that roll their own U8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A draft, for consideration: take it, change it or close it. It adds 8- and 16-bit word types to Base. I know bytes are
U32by ruling today (tests/base/bytes_ops.bend, andFile.read_bytes/TCP.send_bytestakeList<&2, U32>), so this is an option, not a request to change that.Why it might be worth having. A typed byte makes wrapping at 8 bits, byte order and range part of the type, which suits proofs about encodings: UTF-8, checksums, crypto, wire formats. Several hub packages build their own version today.
What it adds (250 lines of
base.bend, plus a test):type Byte is Data: Byte{data: Word(8n)}andtype Word16 is Data: Word16{data: Word(16n)}, built the wayU32is:add sub mul and or xor not inc shl shr, which wrap;cmp is_eq is_lt is_le is_gt is_ge;to_nat to_u32 from_nat show.U32.to_byteandU32.to_word16, which keep the low bits.U32.byte(a, i), byteiofa, least significant first.U32.of_bytes(b0, b1, b2, b3), least significant first, andU32.of_bytes_be, most significant first.Word16.of_bytes.Word.lo,Word.hiandWord.cat, to split aWord(m + n)and join it back.Byte.to_u32_to_byte:U32.to_byte(Byte.to_u32(b)) == b, proved by cases on the 8 bits.There are no natives, so these run as Base defs in every lane. Natives can follow if you want them.
The names.
U8andU16would be the natural names, but 11 hub packages declare their ownU8(3 also declareU16). A redeclared Base name is refused (#1042), so those packages, and 6 files that import them, would stop checking. Eight of the 11 are UTF-8 decoders whereU8is the decoder's state, not a byte.ByteandWord16collide with nothing:--check-onlyoutput with this Base as withmain's.Tested on
mainat e5527d5:tests/base/byte_word16.bend: the interpreter, JS and C lanes all print the expected line, and--verdictprints ALL PROOFS CHECK. So does Base on its own.--check-onlyoutput is identical with this Base and withmain's.Not run:
gates/test.tsandgates/safe.tson the minis.If you'd rather not grow Base, I'll publish it as a hub package instead.
Found and tested with Claude Code, running Claude Opus 5.5, during an audit of
--verdict.