Hacker News new | past | comments | ask | show | jobs | submit login

> The first one that comes to mind is its arbitrary-sized integers. That sounds weird at first, but yes, you can have the regular u8, u16, u32 etc., but also u3. At first it might sound like dark magic, but it makes sense with a good example that is actually a defect in Rust to me.

You don't need Rust to support that because it can be implemented externally. For example, crates like "bitbybit" and "arbitrary-int" provide that functionality, and more:

https://docs.rs/crate/arbitrary-int/

https://docs.rs/crate/bitbybit/




I'm normally not sympathetic to the "you don't need that" argument, but there is a much stronger argument for not having arbitrarily-sized integers in Rust: the fact that values of such types can't have an address. The reason why our types all have bit sizes measured in octets is that a byte is the minimum granularity for a pointer.


They could just be aligend and padded to the next power of 2, right? I think they work like that in Zig and only when they are put in a (bit)packed struct are they actually (bit)unaligned and unpadded.


A byte isn't the minimum granularity for a pointer. The minimum is based on whatever target you're compiling for. If it's a 32-bit target platform, then the minimum granularity is 4 bytes. Why should pointer size determine value size though? It's super fast to shift bits around, too, when needed.


> If it's a 32-bit target platform, then the minimum granularity is 4 bytes.

Huh? How do you think `const char *s = "Hello"; const char *t = &s[1];` works?

> Why should pointer size determine value size though?

Because you should be able to take the address of any value, and addresses have byte granularity.


> Because you should be able to take the address of any value

That's debatable, though. One could argue that languages should explicitly support "values that are never going to have their address taken, be passed by reference/pointer, etc." which would only become addressable, e.g. as part of a struct.


C and C++ (the latter unofficially, IIRC) have this with bitfield types, and they aren't very well loved, precisely because they aren't addressable.


> Huh? How do you think `const char s = "Hello"; const char t = &s[1];` works?

I think you and the parent are using different definitions of granularity. The parent meant that sizeof(t) could be 32 or 64 bits. I think you just meant that the smallest thing the pointer references is the address of a single byte.

Rust already has fat pointers though. A reference to a smaller byte value could be a pointer plus a bit-mask.


With a 64 bit pointer you could make it bit addressable.


At that cost of having your loads no longer be hardware load instructions, which would be bad for performance.


High performance memory systems aren't register based anyways.


> Huh? How do you think `const char s = "Hello"; const char t = &s[1];` works?

So this is just an example of a pointer offset by 1 slot. It's not conceptually all that different to take sub-values of a slot.

To work with values that consume fractions of a byte, such as a 3-bit integer, a pointer + a bit offset is used to grab that value (that complexity is abstracted by the compiler). My argument is the bit shift necessary to load the 3-bits you need from the 8-bit slot is one of the cheapest operations a CPU can do. Meanwhile using 3-bits when all you need is 3-bits allows for things like arrays and packed structs to use much less memory than padding everything to 8 bits.

And why shouldn't a language support that?


If your pointers have to have a bit offset, then now a pointer isn't just 1 hardware word, which would be odd to say the least for a systems language. (It would also be slow, because making a load anything other than a load is something you really don't want to do; you would lose the ability to fold into addressing modes on x86 in many cases for example.)

If some pointers have a bit offset but others don't, OK, I guess, but I'd argue that at that point it'd be a cleaner design to just have a "pointer plus bit offset" be a separate type from "regular pointer". And that would get back to the problem that you would have a type that you couldn't take a "regular" pointer to.


Just to close the loop here, it looks like that is exactly what zig does for pointers, such that there is a different type of pointer for each combination of bit offsets and byte alignments, and yes it is distinct from a "regular" pointer (of which there isn't one "regular" type either, but also many separate flavors, including C-compatible, single-item, and many-item): https://ziglang.org/documentation/master/#toc-packed-struct




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: