Live data from Hacker News

Zig feels more practical than Rust for real-world CLI tools

dayvster.com

391–400 of 412 posts

Re: Zig feels more practical than Rust for real-world CLI tools

#391

Earlier quoted context omitted.

The tradeoff is between performance, safety and ergonomics. With GC languages you lose the first one.

> The tradeoff is between performance, safety and ergonomics. With GC languages you lose the first one. That's a myth that just won't die. How is it that people simultaneously believe 1) GC makes a language slow, and 2) Go is fast? Go's also isn't the only safe GC. There are plenty of good options out there. You are unlikely to encounter a performance issue using one of these languages that you could resolve only wit…

Go is middle-pack fast, not fast-fast.

There are always going to be problem sets where the GC causes significant slowdown.

Re: Zig feels more practical than Rust for real-world CLI tools

#392

Earlier quoted context omitted.

I think you are clearly good-faith. The issue is the underlying and unfair assumption that is so common in these debates: that the memory-unsafe language we're comparing against Rust is always C/C++, rather than a modern approach like Zig or Odin (which will share many arguments against C/C++). You can prove to yourself this happens by looking around this thread! The topic is Zig vs. Rust and just look at how many pr…

The ergonomics of Odin are ghastly, it's all special cases all the time. For example, in Rust when we write `for n in 0..10 {` that 0..10 is a Range, we can make one of those, we can store one in a variable, Range is a type. In Odin `for i in 0.. in Rust we can `for puppy in litter {` and litter - whatever type that is - just has to implement IntoIterator, the trait for things which know how to be iterated, and they…

It's called simplicity.

Not every single semantic element in the language needs to be a type.

`for i in 0..This isn't "magic," it's a loop that initializes a value `i` and checks against it. It's a lot less "magic" than Rust. The iterable types in Odin are slices and arrays - that is hardly arbitrary like you imply.

The type system in Rust is mostly useful for its static guarantees. Using it for type-gymnastics and unnecessary abstractions is ugly and performative.

Tasks in Odin can be accomplished with simplicity.

The C++ misdirection and unbounded type abstractions are simply not appreciated by many.

If you want a language with no special cases that is 100% fully abstract then program in a Turing machine. I'll take the language designed to make computers perform actions over a language having an identity crisis with mathematics research, all else equal. Unless I'm doing math research of course - Haskell can be quite fun!

Ginger Bill is a PhD physicist as well -- not that education confers wisdom -- but I don't bet his design choices are coming from a resentment of math or abstraction.

Absolute generality isn't the boon you think it is.

Re: Zig feels more practical than Rust for real-world CLI tools

#393

Earlier quoted context omitted.

Out of curiosity, why are you borrowing that many times? The following should work: while let Some(page) = object_stream.next().await { match page { // ListObjectsV2Output Ok(p) => { if let Some(contents) = p.contents { all_objects.extend(contents); } } // SdkError Err(err) => { let raw_response = err.raw_response(); let service_error = err.as_service_error(); error!("ListObjectsV2Error: {:?} {:?}", service_error, ra…

Excellent! Thank you! My problem is that I should have something like (http_status, reason) where http_status is a String or u16, reason is a enum with SomeError(String) structure. So essentially having a flat meaningful structure instead of this what we currently have. I do not have any mental model about the error structure of the AWS libs or don't even know where to start to create that mental model. As a result I…

You might want to look at anyhow and thiserror, the former for applications and for libraries the latter. thiserror "just" makes it easier to do what I suggested of writing a manual `impl From` so that `?` can transform from the error you're getting to the error you want. When the API you consume is very granular, that's actually great because it means that you have a lot of control over the transformation (it's hard to add detail that isn't already there), but it can be annoying when you don't care about that granularity (like when you just want to emit an error during shutdown or log during recovery).

https://momori.dev/posts/rust-error-handling-thiserror-anyho...

burntsushi has a good writeup about their difference in usecase here:

https://www.reddit.com/r/rust/comments/1cnhy7d/whats_the_wis...

Re: Zig feels more practical than Rust for real-world CLI tools

#394
post #286

Earlier quoted context omitted.

It's an amazing piece of marketing to corner anyone who dislikes a certain hassle as being mentally deficient - that's what "skill issue" means in this context.

> that's what "skill issue" means in this context. “Skill issue” definitely does not means “mentally deficient”. It comes from the videogames world, where it is used to disparage the lack of training/natural ability of other players; frequently accompanied by “get good”, i.e. continue training & grinding to up your skill.

Do I have to put the pieces together for you? What is the relevant skill in programming? Problem solving. It's not aim or timing or hand-eye coordination lmao.

Re: Zig feels more practical than Rust for real-world CLI tools

#395
post #279

Earlier quoted context omitted.

> Rust has slower compile times That's true. > for the sake of safety, That's false though. All deep dives in the topic find that the core issue is the sheer amount of unoptimized IR that is thrown at LLVM, especially due to the pervasive monomorphization of everything.

Well it is arguably Rust's worst issue and it has remained it for most of its life. Are you really going to try and convince people that this is completely incidental and not a result of pursuing its robust static contracts? How pedantic should we about about it?

On the one hand, you talk about being upfront and honest about trade-offs. On the other, you yourself are being less that credible by phrasing wild speculation as if they are facts.

So... do I as I say, not as I do?

Re: Zig feels more practical than Rust for real-world CLI tools

#396

Earlier quoted context omitted.

> it's a universal tradeoff, that is: Safety is less ergonomic. I'm not sure that that tradeoff is quite so universal. GC'd languages (or even GC'd implementations like Fil-C) are equally or even more memory-safe than Rust but aren't necessarily any less ergonomic. If anything, it's not an uncommon position that GC'd languages are more ergonomic since they don't forbid some useful patterns that are difficult or impos…

GCed languages aren't (usually) more memory safe than safe Rust because they (usually) lack the equivalent to the Send and Sync traits and thus will not prevent unsynchronized access to the same from multiple threads, including data races. Some languages might define data races to not be UB (at least Java and OCaml do this, but Go famously doesn't), but even in those languages data races may produce garbage data due…

> GCed languages aren't (usually) more memory safe than safe Rust because they (usually) lack the equivalent to the Send and Sync traits and thus will not prevent unsynchronized access to the same from multiple threads, including data races.

To be honest that particular aspect of Rust's memory safety story slipped my mind when I wrote that comment. I was thinking of Java's upcoming (?) disabling-by-default of sun.misc.Unsafe which allows you to ensure that you have no unsafe code at all in your program and your dependency tree outside of the JVM itself. To be fair, that's admittedly not quite the same level of memory safety improvement over Rust as Rust/Java/C#/etc. over C/C++/etc., but I felt it's a nice guarantee to have available.

> Guaranteed thread safety is huge.

I totally agree! It's not the only way to get memory safety, but I definitely lean towards that approach over defining data races to be safe.

Re: Zig feels more practical than Rust for real-world CLI tools

#397

Earlier quoted context omitted.

Memory safe doesn't mean protection from integer overflow unless you use that integer to index into some array. I'm not sure how you'd enter NULL given scanf.

I'm not sure how showing that gp can't even write a dozen lines of memory safe C proves that doing so for the exponentially harder 100+k LoC projects is feasible. The program contains potential use of uninitialized memory UB, because scanf error return is not checked and num1 and num2 are not default initialized. And a + b can invoke signed integer overflow UB. A program with more than zero UB cannot be considered me…

> num1 and num2 are not default initialized

num1 and num2 are declared on the stack and not the heap. The lifetimes of the variables are scoped to the function and so they are initialized. Their actual values are implementation-specific ("undefined behavior") but there is no uninitialized memory.

> And a + b can invoke signed integer overflow UB. A program with more than zero UB cannot be considered memory safe.

No, memory safety is not undefined behavior. In fact Rust also silently allows signed integer overflow.

Remember, the reason memory safety is important is because it allows for untrusted code execution. Importantly here, even if you ignore scanf errors and integer overflow, this program accesses no memory that is not stack local. Now if one of these variables was cast into a pointer and used to index into a non-bounds-checked array then yes that would be memory unsafety. But the bigger code smell there is to cast an index into a pointer without doing any bounds checking.

That's sort of what storing indexes separately from references in a lot of Rust structures is doing inadvertently. It's validating accesses into a structure.

Re: Zig feels more practical than Rust for real-world CLI tools

#398
post #286

Earlier quoted context omitted.

> that's what "skill issue" means in this context. “Skill issue” definitely does not means “mentally deficient”. It comes from the videogames world, where it is used to disparage the lack of training/natural ability of other players; frequently accompanied by “get good”, i.e. continue training & grinding to up your skill.

Do I have to put the pieces together for you? What is the relevant skill in programming? Problem solving. It's not aim or timing or hand-eye coordination lmao.

Not sure I get your point. One can definitely "get good" at problem solving. Isn't that the whole purpose of Leetcode and whatnot?

I struggled with Rust at first but now it feels quite natural, and is the language I use at work and for my open-source work.

I was not "mentally deficient" when I struggled with Rust (at least that I know of :v), while you could say I had a skill issue with the language

Re: Zig feels more practical than Rust for real-world CLI tools

#399

The benefit of Zig seems to be that it allows you to keep thinking like a C programmer. That may be great, but to a certain extent it’s also just a question of habit. Seasoned Rust coders don’t spend time fighting the borrow checker - their code is already written in a way that just works. Once you’ve been using Rust for a while, you don’t have to “restructure” your code to please the borrow checker, because you’ve a…

> Seasoned Rust coders don’t spend time fighting the borrow checker No true scotsman would ever be confused by the borrow checker. i've seen plenty of rust projects open source and otherwise that utilise Arc heavily or use clone and/or copy all over the place.

Why would using Arc mean that someone is fighting the borrow checker, or confused by it?

Would you also say the same for a C++ project that uses shared_ptrs everywhere?

The clone quip doesn't work super well when comparing to C++ since that language "clones" data implicitly all the time

Re: Zig feels more practical than Rust for real-world CLI tools

#400

Earlier quoted context omitted.

The ergonomics of Odin are ghastly, it's all special cases all the time. For example, in Rust when we write `for n in 0..10 {` that 0..10 is a Range, we can make one of those, we can store one in a variable, Range is a type. In Odin `for i in 0.. in Rust we can `for puppy in litter {` and litter - whatever type that is - just has to implement IntoIterator, the trait for things which know how to be iterated, and they…

It's called simplicity. Not every single semantic element in the language needs to be a type. `for i in 0.. This isn't "magic," it's a loop that initializes a value `i` and checks against it. It's a lot less "magic" than Rust. The iterable types in Odin are slices and arrays - that is hardly arbitrary like you imply. The type system in Rust is mostly useful for its static guarantees. Using it for type-gymnastics and…

The "simplicity" you're so happy about means you only get whatever it is Bill made. If that doesn't work for Bill he'll fix it, but if it doesn't work for you (and at scale, it won't) too bad.

Far from just the two special cases you listed I count five, Bill has found need for iterating over:

Both built-in array types, strings (but not cstrings), slices and maps.

`for a, b in c { ... }` makes a the key and b the value if c is a map, but if c were instead an array then a is the value and b is an index. Presumably both these ideas were useful to Bill and the lack of coherence didn't bother him.

Maps are a particularly interesting choice of built-in. We could argue about exactly how a built-in string type should best work, or the growth policy for a mediocre growable array type - and Odin offers two approaches for strings (though not with the same support), but for maps you clearly need implementation options. and instead in the name of "simplicity" Bill locks you into his choice.

You're stuck with Bill's choice of hash, Bill's layout, and Bill's semantics. If you want your own "hash table" type that's not map yours will have even worse ergonomics and you can't fix it. Yours can't be iterated with a for loop, it can't be special case initialized even if your users enabled that for the built-in type, and of course all the familiar functions and function groups don't work for your type.

I don't have a use for a "language designed to make computers perform actions" when it lacks the fine control needed to get the best out of the machine but insists I must put in all the hard work anyway.

Post reply on HN