Live data from Hacker News

Unsafe Zig Is Safer Than Unsafe Rust

andrewkelley.me

101–105 of 105 posts

Re: Unsafe Zig Is Safer Than Unsafe Rust

#101
post #87
post #33

Earlier quoted context omitted.

> Rust's system for external C calls should be more like that and less about casts to raw pointers. It seems a rosy-eyed view to think that this would helping safety significantly, and would require a lot of effort: it's likely to be much lower pay-off than other things, like investing in, say, sanitizers or even just doing the work of writing safe wrappers for popular C libs, removing C FFI concerns from most people…

Of course you want to use Rust slices. Those map directly to the kind of C array I outlined. If you could declare a C API that way to Rust, you'd get the mapping without talking about pointers explicitly at all. What I'm arguing for is a declarative way to talk about C interfaces that is consistent with Rust's model. This is better than using "unsafe" to construct C-type raw pointers. Yes, this is more restrictive an…

What would make this "declarative way to talk about C interfaces" less error prone than something like this?

    extern fn read(fd: c_int, buf: *mut c_char, len: usize) -> isize;

    pub fn read(fd: c_int, buf: &mut [c_char]) -> isize {
        unsafe { read(fd, buf.as_mut(), buf.len()) }
    }
Further, note that this is insufficient for an idiomatic Rust API. You would also want to wrap the file descriptor (perhaps not for all C APIs) and the return value (definitely applies to all C APIs). So it would really look more like this:

    pub struct File { fd: c_int }

    impl File {
        pub fn read(&self, buf: &mut [u8]) -> Result {
            let r = unsafe { read(self.fd, buf.as_mut(), buf.len()) };
            if r == -1 {
                Err(ReadError::from(errno))
            } else {
                Ok(r as usize)
            }
        }
    }
I can certainly imagine a way to do that declaratively, but not in a way that helps even this most basic of examples. (Also, note that constructing raw pointers is completely safe- `as_mut` for example.)

Re: Unsafe Zig Is Safer Than Unsafe Rust

#102
post #62

Earlier quoted context omitted.

I'll be an anti-crustangelist and say that I've actually avoided moving a C++ project I've been working on over to Rust because (1) I'm finding that fixing some of the previous code's pre-C++xx practices is suitable enough and (2) I've only written a few small things in Rust up to this point and learning the 30% or so more that I'd need to in order to get things fixed would take more time and has more unknowns. Grant…

Well, if you want to write a tree using indices in a local array instead of pointers for better locality and memory footprint (which is ideal for many situations), you run into the difference between language pointers and computer science pointers. That's not even something that Rust will be smart enough to help you do properly.

Rust can totally help you do that properly. You can wrap the indices in a struct parameterized by a lifetime and regain all the same tools you would have with language pointers.

Re: Unsafe Zig Is Safer Than Unsafe Rust

#103
post #98

Earlier quoted context omitted.

Well, if you want to write a tree using indices in a local array instead of pointers for better locality and memory footprint (which is ideal for many situations), you run into the difference between language pointers and computer science pointers. That's not even something that Rust will be smart enough to help you do properly.

In fact (unless something has changed dramatically without my getting the memo), that's how you would write many data structures in Rust---either for better memory behavior or you have cycles and Rc won't cut it. You have to use a vector of nodes and indices as pointers; if you try using references, the borrow checker comes and kicks sand in your face.

It's doable to keep using pointers instead of indices- they just all have the lifetime of the vector and you can freely follow them around.

This does prevent resizing the vector, but you can get around that by using a different arena that allocates in chunks rather than reallocating (and thus doesn't require a unique reference for .insert).

Re: Unsafe Zig Is Safer Than Unsafe Rust

#104
post #101
post #87

Earlier quoted context omitted.

Of course you want to use Rust slices. Those map directly to the kind of C array I outlined. If you could declare a C API that way to Rust, you'd get the mapping without talking about pointers explicitly at all. What I'm arguing for is a declarative way to talk about C interfaces that is consistent with Rust's model. This is better than using "unsafe" to construct C-type raw pointers. Yes, this is more restrictive an…

What would make this "declarative way to talk about C interfaces" less error prone than something like this? extern fn read(fd: c_int, buf: *mut c_char, len: usize) -> isize; pub fn read(fd: c_int, buf: &mut [c_char]) -> isize { unsafe { read(fd, buf.as_mut(), buf.len()) } } Further, note that this is insufficient for an idiomatic Rust API. You would also want to wrap the file descriptor (perhaps not for all C APIs)…

That's not bad. It would be useful to be able to use some kind of "C slice" in an extern fn declaration, so you could talk about arrays, rather than pointers. Same function call code, but more Rust-line syntax. Then you don't need unsafe imperative code at all.

This would put all the memory-risky stuff in declarations of external functions.

Re: Unsafe Zig Is Safer Than Unsafe Rust

#105
post #29

I'd like to see a C equivalent of this, just for comparisons sake to zig

#include #include typedef struct { int32_t a; int32_t b; } Foo; int main(void) { uint8_t array[1024]; memset(array, 1, sizeof(array)); Foo *foo = (Foo*)(&array[0]); foo->a += 1; } Using clang 3.8.0-2. Compiling examples with `clang -S llvm-ir`. It appears that the array is aligned with the minimum ABI requirement 16 by default? May be a note of this in the standard, can't recall of the top of my head. %array = alloca…

Also curious, would one ever do this in C? I understand the need in Rust and Zig, but in C is this usual?
Post reply on HN