* I don't think that low level code needs to be "messy", and
* I don't think that adding an abstraction on top solves anything complexity wise.
For memory paging I used to have a whole library in Rust that handled hierarchy of page tables with very abstract pagetable classes and interfaces [0]. Now I just have 80 lines of zig that handles everything [1]. I much prefer the latter.
> I think this is reasonable even for kernel code.
It's not, for some of the reasons that Linus doesn't want C++ code in the kernel [2]
[0] https://github.com/gz/rust-x86/blob/28d5839933973e0b639ef354...
[1] https://git.sr.ht/~jzck/kernel/tree/master/src/arch/x86/pagi...
I don't think what Linus wrote in 2004 on C++ has much relevance for 2020 Rust, especially for a new kernel that doesn't have a ton of contributors. Most of his complaints seem to be on how C++ abstractions can make it hard to review unknown code and how 2004 C++ code bases often had extremely messy code. Rust IMO doesn't suffer from those problems near as much as 2004 C++ did.
Also, Google is using Rust for part of their new Fuchsia kernel so at least they think Rust has something good to offer kernel dev.
No, it's written in C++[1]. They're very different languages.
That said, Google seems to think C++ has something to offer to all kinds of development. It seems to work for them, but they are a heavily C++ shop. I wouldn't read too much out of their use of C++ anywhere; it'd be more surprising and interesting to see them use anything else.
[1]: https://fuchsia.googlesource.com/fuchsia/+/master/zircon/ker...
[0]: https://fuchsia.dev/fuchsia-src/concepts/kernel/zx_and_lk
Output:
Test [1/1] test "bit field access"...
*align(:3:1) u3
All 1 tests passed.
Zig's pointer type has optional metadata to describe alignment, sub-byte offset, and SIMD vector element index. This generally makes things just work, and you'll get a compile error if you expected an unadorned aligned pointer. If I were to swap: - fn deref(ptr: var) u3 {
+ fn deref(ptr: *u3) u3 {
Then I'd get: test.zig:13:23: error: expected type '*u3', found '*align(:3:1) u3'
assert(deref(&data.b) == 2);
^This is the main risk with bitfields in C, it makes reads and writes that appear to be independent actually access the same memory cell behind the scenes. I'm not convinced by the idea of adding even more magic on top of it to be honest, it is true that packing and unpacking bitfields is annoying and requires some boilerplate but in the end that is how it the hardware does it anyway.
Arbitrary sized integers do sound very convenient, although I guess the counterargument would be that they simply can't map to machine types so you'll have to have magic behind the scenes which may not make complete sense in low level languages. Still, C has bitfields in structs which are sort of the same thing so why not.
Pointer handling however I'm not sold on. I'd argue that the very cumbersome pointer handling in Rust is a feature, not a bug. It's explicitly discouraged, and for good reasons. Map your pointer into a clean and safe reference, slice or wrapper object ASAP and leave raw pointers to the messy details of C FFIs and ultra low-level code. If you end up having to mess with raw pointers everywhere in your codebase you're doing it wrong, as far as Rust is concerned.
I think this is reasonable even for kernel code. After all typically you wouldn't dereference register pointers directly in C code because of volatility issues and making it obvious that you're accessing hardware and not RAM (readl/writel or similar), so having a safe wrapper adds no overhead in my experience.