Live data from Hacker News

Unsafe Zig Is Safer Than Unsafe Rust

andrewkelley.me

31–40 of 105 posts

Re: Unsafe Zig Is Safer Than Unsafe Rust

#31
post #26

Zig looks very interesting. There is only TODO in memory section in documentation. From what I understand there is only manual memory management? I've seen there is a mention about custom allocators, any details? Any RAII like concept? or full manual memory management?

Memory is manually managed, yes. We do have defer (as in go) for slightly easier resource management.

Zig doesn't have a default memory allocator. Allocators instead are expected to be passed as an argument to functions as they need them. This makes it trivial to replace an allocator with something custom or use multiple different allocators within a small code block.

A contrived example:

  const std = @import("std");

  pub fn GiveMeAnInt(alloc: &std.mem.Allocator) -> %&u32 {
      return alloc.create(u32);
  }

  test "using two allocators" {
      const int1 = try GiveMeAnInt(std.heap.c_allocator);
      *int1 = 2;
      // Would usually store the allocator with the type on construction.
      defer std.heap.c_allocator.destroy(int1);

      const int2 = try GiveMeAnInt(std.debug.global_allocator);
      *int2 = 2;
  }

Re: Unsafe Zig Is Safer Than Unsafe Rust

#32
post #26

Zig looks very interesting. There is only TODO in memory section in documentation. From what I understand there is only manual memory management? I've seen there is a mention about custom allocators, any details? Any RAII like concept? or full manual memory management?

"Zig does not support RAII or operator overloading because both make it very difficult to tell where function calls happen just by looking at a function body."

more in the 0.1.1 release notes! http://ziglang.org/download/0.1.1/release-notes.html

"Zig's standard library is still very young, but the goal is for every feature that uses an allocator to accept an allocator at runtime, or possibly at either compile time or runtime."

more in this wiki! https://github.com/zig-lang/zig/wiki/Why-Zig-When-There-is-A...

Re: Unsafe Zig Is Safer Than Unsafe Rust

#33
post #20
post #3

Rust is a language that offers you lots of compile time checks, and an escape hatch called unsafe that says “trust the programmer here.” Yes, it is possible—and easy—to make mistakes in the place where you have asked to be trusted, not checked. We have a big pedagogical task ahead of us in teaching safe practices for unsafe Rust, and defensive coding practices in unsafe Rust. We should also think of if we can improve…

Rust's approach to "unsafe" is to let the programmer do whatever they want. Having to use this for UNIX-type API calls is kind of lame. I once proposed extending C to allow talking about array sizes.[1] You'd define "read" as int read(int fd, char &buf[len], size_t len); The compiler now knows that "buf" is an array with length "len", and can check calls for "buf" being the right size. The generated code for the call…

> 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, who can just use the Rust library.

Specifically, as you say, C doesn't have this information, meaning there's no way for Rust's (or another language's) FFI to work like this automatically. Instead, someone will have to annotate the C code, have some extra "notes" layer, or annotate the imported Rust declarations. Either way, there's a human element, meaning a place for mistakes to be made. It seems like the less-duplicative way to do this is to make Rust wrappers that take Rust slices, since these will be wanted in the end anyway.

Re: Unsafe Zig Is Safer Than Unsafe Rust

#34
post #20
post #3

Rust is a language that offers you lots of compile time checks, and an escape hatch called unsafe that says “trust the programmer here.” Yes, it is possible—and easy—to make mistakes in the place where you have asked to be trusted, not checked. We have a big pedagogical task ahead of us in teaching safe practices for unsafe Rust, and defensive coding practices in unsafe Rust. We should also think of if we can improve…

Rust's approach to "unsafe" is to let the programmer do whatever they want. Having to use this for UNIX-type API calls is kind of lame. I once proposed extending C to allow talking about array sizes.[1] You'd define "read" as int read(int fd, char &buf[len], size_t len); The compiler now knows that "buf" is an array with length "len", and can check calls for "buf" being the right size. The generated code for the call…

C99 has this, I believe? https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html

Re: Unsafe Zig Is Safer Than Unsafe Rust

#37

One big glaring flaw IMO is that it is not really possible to just turn off certain checks as opposed to turning them all off. For instance, maybe I need to call an unsafe C api or something but could still use the borrow checker.

In Rust, the borrow checker is still enabled in unsafe blocks.

Re: Unsafe Zig Is Safer Than Unsafe Rust

#38

Earlier quoted context omitted.

Correct me if I’m wrong but I thing GP was stating that composing two “unsafe” blocks together (both of which are manually verified to work well) might interfere with each other when run simultaneously.

Its possible that I misread the comment; it seemed to state that this problem extended into safe Rust, which it definitely does not.

Think of two libraries that use unsafe Rust and interact with the same hardware, but work correctly when used on their own.

A program written only in pure not-unsafe Rust might use these two libraries in a way that breaks because the assertions the programmers of the libaries had, like for example having exclusive access to the hardware, are wrong now.

One could argue the pure not-unsafe Rust program is wrong, not the libraries.

I think klodolph's comment is very thoughtful and shows a good deal of experience and domain knowledge.

Re: Unsafe Zig Is Safer Than Unsafe Rust

#39

One big glaring flaw IMO is that it is not really possible to just turn off certain checks as opposed to turning them all off. For instance, maybe I need to call an unsafe C api or something but could still use the borrow checker.

An `unsafe` block only enables extra features, it doesn't change existing behaviour of safe Rust. Specifically, it allows calling `unsafe` functions (FFI and pure Rust `unsafe` ones), dereferencing raw pointers and some minor other stuff (e.g., inline assembly, some manipulations of packed structs). The borrow checker still works on references, the trait system still enforces Send/Sync for concurrency, and the type system still requires things to have matching types.

It's definitely true that having a one dimensional `unsafe` might seem unnecessarily powerful in some cases (e.g. an particular unsafe block might just need to do some pointer offsetting and dereferencing, but no FFI), but it isn't a "you're on your own" hammer.

Re: Unsafe Zig Is Safer Than Unsafe Rust

#40
post #20

Earlier quoted context omitted.

Rust's approach to "unsafe" is to let the programmer do whatever they want. Having to use this for UNIX-type API calls is kind of lame. I once proposed extending C to allow talking about array sizes.[1] You'd define "read" as int read(int fd, char &buf[len], size_t len); The compiler now knows that "buf" is an array with length "len", and can check calls for "buf" being the right size. The generated code for the call…

C99 has this, I believe? https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html

That's for local variables. Microsoft and Linus Torvalds didn't like it, because it's a way to suddenly cause unexpected stack growth of arbitrary size. That feature was made optional in C++11, and Microsoft never implemented it.
Post reply on HN