Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I mean, there's no question that Zig, also in its current state, is vast improvement over C or even C++ - for the "small stuff". It is much more pleasant to use.

But there is still the "big stuff" - the things that have a fundamental, architectural impact. Things like: Will my program be multithreaded? Will I have many systems that interact? Will my program be maximally memory-efficient? Do I have the capacity (or money) to ensure correctness if I say "yes" to any of that?

The most important consideration in any software project is managing architectural complexity. Zig is better, yes, but not a paradigm shift. If you say "yes" to any of the above, you are in the same world of pain (or expenses) as you would be in C or C++. This is the reason that Rust is interesting: It makes things feasible/cheap that were previously very hard/expensive, at a fundamental level.



> Zig is better, yes, but not a paradigm shift.

But it doesn't have to be and it shouldn't. Rust also isn't a paradigm shift, it "just" solved static memory safety (admittedly a great engineering feat) but other languages solved memory safety too decades ago, just with more of it happening at runtime.

But in many other areas Rust copied too many bad ideas from C++ (and many of those "other things" Zig already does much better than Rust - but different people will have vastly different opinions about whether one solution is actually better than another - so discussions about those features usually run in circles).

There shouldn't be a single language that solves all problems - this will just result in stagnation, it's much better to have many languages to pick from - and even if they just differ in personal opinions of the language author of how to do things or entirely subjective 'syntax sugar' features. Competition is good, monocultures are bad.

> The most important consideration in any software project is managing architectural complexity

No language will help you managing "architectural complexity" in any meaningful way except by imposing tons of arbitrary restrictions which then get in the way for smaller projects that don't need much "architecture". We have plenty of "Enterprise-scale languages" already (Java, C#, Rust, C++, ...), what we need is more languages for small teams that don't get in the way of just getting shit done, since the really interesting and innovative stuff doesn't happen in enterprise environments but in small 'basement and bedroom teams' :)


You put "just" in scare quotes, but that word does a lot of heavy lifting there. Static memory safety is an extremely useful thing, because it enables you to do things competent programmers would never dare in C, C++, or Zig. Things like borrowing data from one thread's stack in another thread, or returning anything but `std::string` from a function. These things were simply not feasible before without a huge bulky runtime and GC.

Keep in mind that Rust's definition of "memory safety" covers much more than just use-after-free, the most important being thread safety. It is a blanket guarantee of no undefined behavior in any code that doesn't contain the word `unsafe`. Undefined behavior, including data race conditions, is a major time sink in all non-hobby C or C++ projects.

What bad ideas from C++ did Rust copy, in your opinion? I'm really not sure what you mean. Smart pointers? RAII?

There are plenty of languages that enable quick iteration, prototyping, or "just getting shit done". If that's what you need, why not use them? I'm personally more concerned about the finished product.


You know, I'm beginning to understand why people complain about the "Rust Evangelism Strike Force". Can we discuss a language without the constant "But why not Rust instead?!", pretty please?


I did not bring up Rust.

What are you saying? Do you think I was sent here by some sinister cabal that organizes an effort to direct any discussion about programming towards Rust?


> You put "just" in scare quotes

...I don't use them as "scare quotes", it's more like in "can't you just..." - e.g. something that looks simple from the outside but is hard to do / complex on the inside - e.g. I do recognize the work that went into Rust's memory safety, but I question the effort that went into it compared to more traditional memory safety methods, especially when looking at the restrictions that Rust imposed on the programmer - it's a pretty hefty tradeoff (IMHO of course).

> What bad ideas from C++ did Rust copy, in your opinion?

Mainly doing things in the stdlib that should be built into the language (e.g. Option, Result, Box, Cell, RefCell, Arc, and probably a dozen other types and traits...), resulting in what I call 'bird droppings syntax' of too many chained function calls to get to the thing you actually want (.unwrap, .into_iter, .iter, .iter_mut, .as_ref, .as_mut, .expect, .unwrap_or_else, .unwrap_or_default, .ok, .ok_or_else, .and_then, .or_else ... like, wtf?). The absurd amount of `::` and `<>` in typical Rust code. The missing separation line between stdlib and language (like for-loops using the Iterator trait, or more obviously: operator overloading). The stdlib doing memory allocations behind your back through a global allocator - which we know from C++ do be a really bad idea for decades already... etc etc... I think most Rust programmers are blind towards those issues the same way that C++ programmers are blind towards C++ issues (which is another thing both language ecosystems have in common though).


I mean, there's no winning here. Either the language is too complex and does too many things, or it's not complex enough and relegates fundamental things to the standard library.

I don't thing there is any substantial difference between `Option<Thing>` and `@Nullable Thing` or `Thing | null`, I don't think there's anything wrong with choosing `::` over `.` for namespace resolution (it means you can have local variables with the same name as a module), and you have to have some way to declare generic parameters.

Rust generally does not allocate behind your back, but custom allocators is a work in progress. The reason it takes time is precisely that they want to avoid the mistakes of C++. A couple of mistakes were already avoided - for example, async/await in Rust does not allocate behind your back, while C++ coroutines do.


> I don't thing there is any substantial difference between `Option<Thing>` and `@Nullable Thing` or `Thing | null`

I object to @Nullable and similar arrangements as a magic special case. If the sum types only solved this one issue then it's a wash but they do a lot more too.

Either of the sum types, the concrete `Option<Thing>` or the ad hoc `Thing | null` are OK because they're not magic, less magic is better.


I’m confused. You seem to think Option is magical? It is not, and neither is Result. They are regular sum types defined in the standard library, nothing special about them.


That's certainly not what I was trying to get across. Perhaps I wrote something confusing, for which I apologise, but, since we're here anyway...

Technically Option is actually magic, though it's for a subtle reason unconnected to the current topic. If you go read its source Option is a langitem, that is, Rust literally isn't allowed to exist without this type. Rust's core libraries are defined, so you shouldn't and most people never will use Rust without them, but the Rust language actually doesn't require that all of core exists, it does require a handful of types, functions etc. and those are called "langitems".

So, why is Option a langitem? Well, Rust's language has for-each loops. But what it actually does (there's literally a compiler step doing this) is treat those loops as if they'd been written as a slightly clunky loop { } block making and then consuming an Iterator. To do that the IntoIterator and Iterator traits must exist, and further as the return type from the next call needed in Iterator is an Option the Option generic type must exist too!

Technically this type wouldn't have to be called Option, the Rust compiler doesn't care what it is called, but it must exist or else the compiler doesn't know how a for-each loop can work.


Being a langitem means that the compiler can use it in desugaring, and `for ... in ...` happens to be syntactic sugar in Rust, just like `for (auto x: y) {}` is in C++. `Range` et al are also compiler builtins, because `a..b` desugars to that type. It doesn't imply that the type itself is a compiler builtin, for example.

Another example is the `Deref` trait, which roughly corresponds to `operator->()` or `operator*()`, or an implicit reference conversion. It is called implicitly so you can use `smart_ptr.foo` without special syntax for dereferencing.

I think I fundamentally don't understand why any of this is a problem?


I think maybe your fundamental misunderstanding was just a misreading of what I actually wrote?

I don't like @Nullable (or the ? syntax used in C# for example) because they're a special case magic. They handle exactly one narrow idea (Tony's Billion Dollar Mistake, the "null" pointer) and nothing else.

I prefer sum types - both Option<T> and T | null are syntax for sum types. The former, which Rust has, is an explicit generic type, while the latter is an ad hoc typing feature. I don't have a strong preference between them.


doesn't the llvm coroutines require c's malloc? this is part of the reason why zig scrapped async. i would suspect Rust's async/await does allocate behind your back


Rust does not. It also doesn’t use LLVM’s coroutines.


thanks for clarifying




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: