18 ms·
Zig as an alternative to writing unsafe Rust
- evnix 4y agoI you look at Deno and Bun, TS/JS runtimes, one written in rust and the other in Zig. Bun repo is filled with issues surrounding segfaults, but I guess it gave them the advantage to get up and running quickly.
- nvrspyx 4y agoThe link is down for me. Perhaps HN hug of death? Below is link to the site on the Wayback Machine. https://web.archive.org/web/20230307172822/https://zackoverflow.dev/writing/unsafe-rust-vs-zig/ https://web.archive.org/web/20230307172822/https://zackoverf...
- mercurywells 4y agoMaybe you don't have *.dev lookups working properly?
- graypegg 4y agoCheck your hosts file, you might be mapping *.dev to localhost
- yonrg 4y agoI did not know host file takes domain name patterns
- tambourine_man 4y agoBy default, macOS and Linux don’t, but dnsmasq does and it’s quite popular. Don’t know about Windows
- jrsyo 4y agoTry ping "zackoverflow.dev" and "cname.vercel-dns.com". If only the former times out, it's possible your local ISP is blocking Vercel's IP. If that's the case, you could contact Vercel support to help assist.
- bpolverini 4y agoI buy the premise that Zig is better if you know you will have lots of pointer arithmetic going on. Having written a fair amount of unsafe C interop code in Rust, I feel like these critiques of the ergonomics are valid. The new #![feature(strict_provenance)] adds a new layer of complexity, that, I hope, improves some of this experience while adding safety. Rust's benefits are not free. The benefits of Rust's (wonderful) model around references and lifetimes come at a significant cost to ergonomics when having to go into the Mordor of some C library and back. I usually find myself wishing I could have some macro where I just write in C and have it exposed as an unsafe back in Rust. I know I can do this by just writing a C dylib and integrating that, but now I've got two problems. Even still, I prefer writing unsafe Rust to writing C. std::mem::ptr forces me to ask the right questions and reminds me of just how easy it is to fall into UB in C as well.
- WalterBright 4y ago> I usually find myself wishing I could have some macro where I just write in C and have it exposed as an unsafe back in Rust. In D you can just import a .c file mycfile.c with: import mycfile; // C file filled with C functions and they'll be treated as @system code by the D semantics. They're even inlinable.
- swsieber 4y agoHere's one that does that: https://lib.rs/crates/inline-c https://lib.rs/crates/inline-c I'm not sure it's what you're looking for, but it seems like a good starting point. As for the general thrust of your comment and the article, I agree. It'll be interesting to see what changes come to make things nicer.
- zdimension 4y agoThis one runs the C code as a program, so the code doesn't really communicate. I made a proof of concept some time ago of a macro that really translates C to Rust at compile time: https://github.com/zdimension/embed-c https://github.com/zdimension/embed-c
- likeabbas 4y ago
- pyrolistical 4y agoIsn’t var ptr: [*]u8 = @ptrCast([*]u8, &slice[0]); the same as var ptr = slice.ptr; ? Or am I missing something
- WalterBright 4y agoThe `slice.ptr` version is allowed in D, but `&slice[0]` is preferred because that comes with a check that the slice has a non-zero length and the pointer will actually point to something valid. That's why the former is allowed in @system code, and the latter is used in @safe code.
- nektro 4y agoyes it would be the same
- ok123456 4y agoThis pretty much mirrors my experience. Rust is the inverse of Perl: It makes the easy stuff hard. Writing basic data structures isn't a niche, esoteric edge case. There may be a crate that "solves" what you're trying to do. But does it rely on the std---(i.e., is it unusable for systems programming)? Is it implemented making gratuitous copies of data everywhere? Does it have a hideous interface which will then pollute all of your interfaces? Does it rely on 'unstable' features? Then, there's the 'community.' It seems to consist solely of extremely online people who get a dopamine hit from both telling people they're doing things wrong and creating the most complex solutions possible. They do this under a thin veneer of forced niceness, but it's not nice at all.
- ilrwbwrkhv 4y agoOn top of that Rust might be the ugliest modern language.
- coliveira 4y agoAgreed, using Rust is like switching a monster (C++) for another even worse. And notice that Rust is not even a mature language, it will get much worse. I will stay with C, thank you.
- ok123456 4y ago'constexpr' and 'auto' in modern C++ can eliminate a large portion of the ugliness. In some cases it can be much more ergonomic than the equivalent Rust.
- pjmlp 4y agoIndeed, one gets to write macro like code on the same language.
- spoiler 4y agoYou can write Rust macros in Rust too, if you wish, but it's a bit more involved (https://doc.rust-lang.org/reference/procedural-macros.html https://doc.rust-lang.org/reference/procedural-macros.html). I realise this isn't the same as constexpr, but I'd argue it's nicer. Rust also has const generics (but they are still a bit shabby in places last time I used them). I for one never liked the constexpr semantic and syntax. Always felt like a... Little pebble in my shoe. Didn't quite annoy me enough not to use it since it was useful, but it was never a comfortable experience.
- satvikpendem 4y agoNote, this is specifically talking about unsafe Rust versus Zig. Personally unsafe does have some rough edges, I'm looking forward to seeing how the Rust team manages to make it better in the future.
- j16sdiz 4y agoUB in unsafe rust sometimes "leaks" outside the unsafe scope and cause crashing elsewhere. If rust can pair with a proof checker and let user write some correctness proof, it can be way more useful than the current borrow checker.
- mr_00ff00 4y agoThe correctness proof idea sounds intriguing. Ada does this already yes? And do you have any examples of where UB from unsafe rust leaks to outside the program? Surely you would look back at the unsafe code always to fix it.
- dist1ll 4y agoThere is a huge body of work around proof-based programming. If you're looking for a full blown SMT solver and general purpose dependently-typed PL have a look at F* https://fstar-lang.org https://fstar-lang.org
- satvikpendem 4y agoAre you talking about Miri, or something even stronger?
- Arnavion 4y agoMiri doesn't do proofs. It only checks the test cases that you run under it.
- satvikpendem 4y agoInteresting, I wonder if there are any good proof verifiers for Rust.
- ksec 4y ago>There are endless debates online about Rust vs. Zig I have never read anything that suggest or argued Zig as better than Rust, or "Rust vs Zig". Not on HN, not on Reddit, not on Twitter. In fact this link / title is the first one. ( I do wish the title was "Unsafe Rust" to better reflect on the content. ) There are however plenty who still prefer Zig over Rust, even knowing when Rust is better. I also want to note RESF generally does not consider "unsafe" Rust to be Rust. Edit: LOL I knew this would be heavily downvoted.
- infamouscow 4y ago[flagged]
- tomtheelder 4y agoMy experience is that I see a LOT more complaints about these sorts of behaviors than I see the actual behavior. I think it's honestly just a meme that's gotten out of hand at this point. Speaking as someone who is not part of the Rust community and knows comparatively little about the language.
- kaba0 4y agoIn my surface-level interactions with the community I have found it to be absolutely kind and helpful.
- infamouscow 4y agoYou must not see the C or C++ threads. :) Virtually every C or C++ thread on HN for the last several years is littered with comments from Rust zealots demonizing and condemning other humans for being working in C or C++ codebases.
- SleepyMyroslav 4y agoC or C++ threads on HN are often not about something great. Recend thread on SHA-3 vulnerabilities as example [0]. If security standards providers fail to write secure C code where does this put average Joe? I mean the whole 'pride' threads of people who 'enjoy writing C' or C++ look as strange on HN as Rust brigading. Its funny how there is no C or C++ pride thread on a day when vulnerabilities hit frontpage. PS. I have never wrote a line of Rust in my life. 20+ years of C++ work. [0] https://news.ycombinator.com/item?id=35050307 https://news.ycombinator.com/item?id=35050307
- Karellen 4y agoWait, the benchmark to find the 35th fibonacci number took 1.077s for the Zig VM vs 1.657s for the Rust VM? I realise that these VMs are going to be totally idiomatic Zig/Rust, with the most straightforward implementation possible, and little-to-no performance tuning, but even so - that's gotta be a typo, right? Or it's actually finding `fib(350)`? Or each "run" is actually finding `fib(35)` 100 (1000?) times?
- fizx 4y agoIt's intentionally using the naive 2^N solution to stress test lots of tiny function calls.
- dhruvdh 4y agoThere is no way it will take a whole second regardless. Even when compiled in debug mode, it takes about 100 ms. Try it here, I had Bing AI write it out - https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=fb977f063a167c6d347e10d302b5fad2 https://play.rust-lang.org/?version=stable&mode=release&edit...
- estebank 4y agoOP isn't talking about the performance of Rust code to calculate fib(35), but rather the performance of a Rust implementation vs a Zig implementation of an interpreted language executing code to calculate fib(35). They are saying that the Rust VM they wrote is slower than the Zig VM they wrote.
- munificent 4y agoAnd, in particular, an interpreted dynamically typed language.
- jeffdn 4y agoFrom a book that was a real joy to read and take one’s first steps into the magical world of compilers —- thank you for writing it!
- pjmlp 4y agoUsing custom allocators to taint memory for security checks is no better than what C and C++ toolchains have been providing for decades. I was already using debug allocators in Visual C++ 5.0, with a memory report at the program exit. For the latest documentation, https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-debug-heap-details?view=msvc-170 https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-...
- henry_viii 4y ago[flagged]
- dang 4y agoWe've already asked you to stop taking HN threads into programming language flamewar. We don't want that here—it's tedious, and leads to repetitive discussions and then nasty ones. No more of this on HN, please.
- woodruffw 4y ago> Unsafe Rust is hard. A lot harder than C, this is because unsafe Rust has a lot of nuanced rules about undefined behaviour (UB) — thanks to the borrow checker — that make it easy to perniciously break things and introduce bugs. I don't think this is correct: Rust makes writing unsafe Rust correctly more onerous than writing C, but the actual rules for undefined behavior are the virtually same as in C: if you alias where you must not, or mutate where you must not, etc. you're in exactly the same boat. In other words: Rust makes it hard to write unsafe Rust correctly, but no harder than writing well-defined C. The only difference is that Rust raises the safety expectations by default, making unsafe Rust look more difficult than C.
- guipsp 4y agoThe rust undefined behaviour rules are stricter than C: mutating a non mutable reference is UB, for example. Non mutable references don't exist in C.
- jcelerier 4y agoI would think that modifying a pointer to a const object, e.g. const int x = 123; const int *px = &x; (*(int*)px) = 456; is very, very UB in C (and most likely will crash on most platforms)
- nyanpasu64 4y agoint x = 123; const int *px = &x; (*(int*)px) = 456; is legal in C. The Rust equivalent using & and &mut is UB. Writing this in Rust using raw pointers requires unsafe blocks everywhere, loses method syntax, has no -> operator, etc.
- woodruffw 4y ago> Non mutable references don't exist in C. Sure they do: C has a well-defined notion of const-correctness. If you mutate through a `const`, you're invoking undefined behavior. Both C and C++ allow you to strip `const` from a const-qualified value or reference, but only under the condition that you don't actually modify that value. Edit: which, in case it isn't clear, means that Rust's UB is exactly the same as C's in this case.
- andrewstuart 4y agoZig seems more simple than Rust. I’m willing to forgoe certain rust features in exchange for simplicity.
- noncoml 4y agoA hammer better at hammering nails than a screwdriver
- DeathArrow 4y agoI get that Zig is better than unsafe Rust. But what about the general use? Is Zig simplicity and speed of writing code worth the trade-off in safety?
- SoraNoTenshi 4y agoI would say that different technologies serve a different purpose. So, saying, that e.g., Zig is generally better or worse than Rust doesn't make any sense to me, as both Languages have a different purpose. I would much rather use Rust to write a Webserver (in production) than in Zig, simply because Rust serves this purpose better than Zig does. And i personally can consider Zig to be my favourite Language. I would also never (at least right now) write Website frontends in either Zig or Rust, i think JavaScript in this case, is the obvious choice, because it has been developed (over years) for this (and unfortunately other) use case(s).
- chubot 4y agoThe way I would frame this is that Rust has static (compile-time) memory management, and that conflicts with dynamic memory management (garbage collection). The boundary is awkward and creates complexity. I wrote a post about problems writing a garbage collector in C++, e.g. annotating the root set, and having precise metadata for tracing. http://www.oilshell.org/blog/2023/01/garbage-collector.html http://www.oilshell.org/blog/2023/01/garbage-collector.html https://news.ycombinator.com/item?id=34350260 https://news.ycombinator.com/item?id=34350260 I linked to this 2016 post about Rust, which makes me think the problem could be worse in Rust, although I haven't tried it: http://blog.pnkfx.org/blog/2016/01/01/gc-and-rust-part-2-roots-of-the-problem/ http://blog.pnkfx.org/blog/2016/01/01/gc-and-rust-part-2-roo... I didn't write as much about bindings to native C++ code, but that's also an issue that you have to think about carefully. CPython has kind of been "stuck" with their API for decades, which exposes reference counting. So it's extraordinarily difficult to move to tracing GC, let alone moving GC, etc. --- On the other hand, there was also a paper that said Rust can be good for writing GCs. Rust as a Language for High Performance GC Implementation https://dl.acm.org/doi/pdf/10.1145/2926697.2926707 https://dl.acm.org/doi/pdf/10.1145/2926697.2926707 However, I'm not sure it addresses the interface issue. One lesson I learned is that GCs are NOT modular pieces of code -- they have "tentacles" that touch the entire program! That said, C++ is pretty good at "typed memory" as well, and I think it's more pleasant than C. That is, you get more than void* and macros. So I can believe that Rust has benefits for writing GC. Not sure about Zig -- I can believe it's a nice middle ground.
- kaba0 4y agoDynamic memory management is an entirely different axes from manual/automatic, though. (Safe) Rust indeed limits the user to a compile-time deallocable subset of what’s expressible (RC being an escape hatch), which depending on the problem domain may be too limiting.
- slaymaker1907 4y agoI think most of the difficulty people experience is when they try to naïvely use references anywhere they would normally use a pointer. That mostly works for functions, but this ends up getting really confusing and difficult for data objects. Instead, people should really be using things like Rc<T> which makes certain patterns much simpler. People seem to have this ridiculous notion that using Rc<T> or heaven forbid Rc<Box<T>> is going to make their code slow, but in reality it can greatly simplify code at minimal performance cost when used places that references would get complex. People generally don't say Swift is slow, but it uses reference counting all over the place.
- lll-o-lll 4y agoPeople do say that Swift is slow though, and it has a whole bunch of optimisations to ensure the RC is elided whenever possible.
- pornel 4y agoThere are two differences from Swift: 1. You don't need to refcount everything. In Swift objects have to be refcounted and heap allocated. In Rust you only use it selectively in cases where shared ownership is really necessary, and otherwise still have an option of using exclusive ownership, value types, etc. 2. You can still borrow Rc's contents locally and use it as a plain reference, so hot loops and leaf functions don't pay the price. Often you may need to touch the refcount only once when building a data structure or passing data to a closure, and then on use it via a temporary reference. In Swift the refcount is updated much more often, and there are only limited cases where ARC optimizer can skip it.
- nextaccountic 4y agoRc<Box<T>> really doesn't make sense (Rc is like a specialized Box), I guess you meant Rc<RefCell<T>>?
- nyanpasu64 4y ago> If I have a raw pointer to an array of data (*mut T), I can turn it into a slice &mut [T], and I get to use a for ... in loop on it or any of the handy iterators (.for_each(), .map(), etc.). I wonder if *mut [u8] would be a workable alternative to &mut [u8]. I haven't looked into creating such pointers yet, but `fn f(a: *mut [u8]) {}` is legal while `fn f(a: *mut [u8]) { a.len(); }` doesn't compile on stable due to https://github.com/rust-lang/rust/issues/71146 https://github.com/rust-lang/rust/issues/71146. Looks like raw slice pointers aren't fully baked yet.
- sundarurfriend 4y agoHow significant is this to embedded development, eg. automotive software? I've been learning Rust on the side, and one of the main applications I have in mind is to get back into some embedded programming. I saw that there were libraries and even whole books about this [1], but I'm curious what the actual experience is like, and how much you have to wrangle raw pointers there. [1] https://docs.rust-embedded.org/book/ https://docs.rust-embedded.org/book/
- steveklabnik 4y agoWe do embedded work at Oxide. There's unsafe code, but not a ton of it. I haven't dug into this project's codebase at all, but the way it's described it sounds like there's way more than we use.
- Animats 4y agoIf you're writing much unsafe code in Rust, you're doing it wrong. OK, for a garbage collector, maybe you have to, because you're taking over memory management yourself. But very, very rarely do you need to do that. And when you do, you need very thorough testing, test tools, and documentation. I just got done chasing someone else's pointer bugs with valgrind and gdb, in C code from a public crate three levels down from my code. Valgrind was useful in locating the area of trouble. The code there had too much unnecessary pointer manipulation, and offsets obtained from input which might be un-initialized memory. This never happens in safe Rust. Which is the whole point. Most things for which C programmers use pointer arithmetic can be expressed as slices. Slices are pointer arithmetic, but with size information and sound rules. (I'm a bit cranky this week. I've spent the last few weeks finding bugs in Rust crates that ought to Just Work.)
- deleted 4y ago[deleted]
- lerno 4y agoThis claim just killed me: "Apart from [Zig] not having crazy UB like in unsafe Rust". Zig has more UB than even C. Yes, Zig has safety checks you can turn on, but then it's not fast anymore. The claim saying Zig has no UB is like saying C has no UB because you can run it with UB-sanitizers. Don't get me wrong, it's great to have this directly enabled in "safe" mode like Zig does it. But to use that to say Zig is more safe is extremely misleading.
- kristoff_it 4y agoYou should read the rest of the article, where the appropriate context is given to that sentence.