Live data from Hacker News

Assorted Thoughts on Zig and Rust

scattered-thoughts.net

261–270 of 307 posts

Re: Assorted Thoughts on Zig and Rust

#261
post #244
post #168

> Zig is dramatically simpler than rust... Most of this difference is not related to lifetimes. I've been thinking about this recently: the borrow checker gets a lot of attention, but I think the majority of the learning curve of rust is actually due to "unforced errors" in the language UX which have nothing to do with the language's core USP's. For instance, the module system just seems needlessly complex. Like you…

I don't think this is fair. There is definitely some unforced error, but a lot of the complexity is shared with other languages in it's heritage eg the trait system is no more complicated than haskell's typeclasses, and haskell also has macro systems on top of that. Also the simplicity in zig comes from a major innovation in controlled partial evaluation, which we've yet to really explore the consequences of. Rust ha…

I mean, if you're saying Rust isn't any more complicated than _Haskell_, I mean, you're not wrong...

[edit: I'd like to clarify that the Rust team has tons of talent and good ideas and can probably find a goal more ambitious than this. Haskell has a definite aesthetic, and it fits some people/projects better than anything else. That aesthetic does not include simplicity.]

Re: Assorted Thoughts on Zig and Rust

#262
post #132

Earlier quoted context omitted.

I've been enjoying D as "C done right". I find it a pleasure to use.

D is much more "C++ done right" (and then some). C and Zig are very barebones, close-to-the-metal language. D has garbage collection, classes, templates, exceptions, built-in dynamic arrays and hash tables, and on and on and on. The "Features Overview" page makes me go cross-eyed [1]. Yes, you can turn many of these things off or ignore them and just use D as a better C, but the same could be said of C++ (for some de…

A common misconception, probably because the majority of D users are C++ veterans. But D was never designed as a successor to C++.

"One of the earliest design decisions that Walter made about D was that it would be easy to use with software written in C. Many widely-used libraries are implemented in C or have a C interface. He wanted to provide an easy path for established software companies to adopt the D language. A straightforward approach was to guarantee that users of D could immediately take advantage of any C library their project required without the need to reimplement it in D." from "Origins of the D programming language" by W.Bright, A.Alexandrescu, M.Parker.

D has an optional conservative mark-sweep Boehm GC which only gets triggered when you attempt to allocate something on the heap. If you don't do that, it won't bother you. Finally, you can explicitly disable it.

People generally ignore or miss the fact that D really shines when it comes CTFE, reflection and metaprogramming.

Re: Assorted Thoughts on Zig and Rust

#263
post #168

> Zig is dramatically simpler than rust... Most of this difference is not related to lifetimes. I've been thinking about this recently: the borrow checker gets a lot of attention, but I think the majority of the learning curve of rust is actually due to "unforced errors" in the language UX which have nothing to do with the language's core USP's. For instance, the module system just seems needlessly complex. Like you…

Another large category of language UX issues is, ironically, the sugar that gets applied to the syntax. The classic example, but far from the only example, is auto-dereferencing: https://stackoverflow.com/questions/28519997/what-are-rusts-...

Rust has many syntax features that can be described as "Rust takes some common pattern that's onerous to write and read, and automatically infers it for you under certain conditions". On its face this seems like a strict improvement: you can still be explicit if you want/need to, or you can skip some boilerplate in certain cases.

But the problem comes when you're trying to learn about the language. Because these UX "optimizations" are layered on fairly arbitrarily - not unlike actual compiler optimizations - they sometimes create a very confusing landscape to try and form a mental model around, in the same way that compiler optimizations can make it hard to understand what will and won't make something faster.

This often plays out as:

1) You have some clean piece of code that does what you want

2) You add something innocuous to it

3) It no longer fits the sugar-pattern that the compiler was silently invoking underneath

4) You now have several sprawling errors because you're expected to be explicit about something you didn't have to be before

An inexperienced Rust programmer would (reasonably) assume those errors were caused by the thing that was added, and start trying to figure out what's wrong with it. But that's a red herring. The real issue, which is not indicated, is that a sugar-pattern was bailed out of.

I'm glad these shortcuts exist in some capacity: Rust is a complicated and fairly verbose language, and they make it less so. But I think they seriously damage the learning experience and early impressions that people form of the language. I've been using it for years and I still discover new quirks with this stuff that I didn't know about, and incorrect assumptions I had about the language itself that were driven by these mysterious mechanisms.

What if rustc had a "no-sugar" mode that people could use until they've gotten a handle on what's really going on? What if the language server somehow indicated inline when sugaring was being invoked?

Edit: A different way of phrasing the problem is that debugging is like navigating a landscape: there's a locality to it. "Did this change bring me closer to my goal, or further away from it? If closer, I'm probably on the right track, if further, probably the wrong one." Most languages mostly adhere to this idea of contiguous space-navigation. But these patterns in Rust are like constructing a maze across the landscape; there are cul-de-sacs and roundabout pathways you have to follow to get where you're going. There's also inconsistency about a given subject: you look at one piece of the terrain from a different angle, and it changes. It's hard to form a coherent, generalized mental map because base truth is relative based on what direction you're coming at it from. So over time instead of learning 2N concepts (lifetimes, references, iterators, boxes) you learn an NxN matrix of concepts (using references with boxes, using references with iterators, using lifetimes with iterators, etc...), because they interact with each other in unpredictable ways.

This may just deserve a whole blog post :)

Re: Assorted Thoughts on Zig and Rust

#264
post #167

Earlier quoted context omitted.

I've been enjoying D as "C done right". I find it a pleasure to use.

D competes more with GC languages like Go and Modula 3, rather than the C / C++ / Rust GCless niche.

This is the first time I see such a comparison :) D is a systems programming language with an optional GC and in the league with C/C++/Rust. I would add Nim and Zig here as well.

Re: Assorted Thoughts on Zig and Rust

#265

I believe if you write tests hooking up your tests with the test allocator will effectively prevent all blatant UAF and memory leak events. More subtle ones that happen due to spooky action at a distance and wierd incomposability might be out of reach. (Not at op, who does write tests:) You are writing tests, right? ;)

Testing is a good way to ensure that your program won't have UAF under most normal circumstances. But when it comes to security it's adversarial - your program will get pushed into parts of the state space that were never seen during testing.

Things like browsers and operating systems are all heavily tested and fuzzed using tools like asan. They still have security issues from UAF.

Re: Assorted Thoughts on Zig and Rust

#266

This is a really great writeup! I was using Rust as my main programming language from some months before 1.0 up until maybe early 2019. I have only written somewhere in between 100 and 1k lines of Zig, but generally feel that I agree with most of what's being brought up here. Here's a mind dump: > Zig manages to provide many of the same features with a single mechanism - compile-time execution of regular zig code. Th…

> > compile-time execution of regular zig code

The problem with this is that it's incompatible with a well-designed compiled[0] programming language; a cross compiler can't replicate the architecture-specific behaviour of the compiled code because the target architecture is unavailable or possibly even nonexistent at the place and time the compiler runs.

Consider, eg, a compiler on ARM targeting x86, when the code uses x86-specific assembly or intrinsics, or more subtly depends on x86-specific handling of things like pointers or integer overflow. If you instead compile the compile-time code for ARM, you a: need two different codegens (soon to become three when you compile the compiler to run on RISC-V), and b: now the compile-time code is depending on ARM-specific semantics, which is even worse.

Giving up on cross compilers means your language isn't well-designed. Giving up on architecture-specific behaviour means your language isn't designed for (direct[0]) compilation. (The latter is a legitimate choice, of course, but its negation is also a legitimate choice, and thus a legitimate reason not to support same-language metaprogramming.)

0: in the sense of C-like compiling directly to equivalent machine code; obviously any language can be compiled in the more general sense of producing a working executable

Re: Assorted Thoughts on Zig and Rust

#267
post #167

Earlier quoted context omitted.

D competes more with GC languages like Go and Modula 3, rather than the C / C++ / Rust GCless niche.

This is the first time I see such a comparison :) D is a systems programming language with an optional GC and in the league with C/C++/Rust. I would add Nim and Zig here as well.

Nim is in the GC category (and its documentation says you should use a refcounting GC rather than turning it off). Zig does not use GC.

Memory management is one of the more important aspects of systems programming so it is useful to be clear about what is the main strategy used by each language.

Re: Assorted Thoughts on Zig and Rust

#268
post #201

Earlier quoted context omitted.

It takes some time to get up to speed with Rust, but I don't think it takes particularly longer to write a correct program in Rust than it does in other languages. I often find myself reaching for Rust rather than Python now, even for small things.

The same is true for C++, and early reaction was similar: hey, we don't need high-level languages anymore! But after a few decades with C++ we've found that the burden manifests not when writing the program but when maintaining a large codebase over many years in a team whose members change over time.

I've used C++ since the 90s and it's only ever been presented as a Serious Language for Real Applications. I feel that until recently, C++ stood alone and there were almost no serious threats to its position, except maybe Java. If you were planning on writing commercial programs (or even more so a collection of programs) that have good performance and huge featuresets, like an operating system or a browser, what else could you have possibly used?

I agree that in practice maintenance has been pretty bad for C++ programs, but I think I understand the kind of reasoning that led so many organizations to pick C++, even if I don't agree with it. It was not about ergonomics or productivity, but about control. The language grants an unprecedented level of power to a small group of elite programmers inside every organization, who author the standard library and headers that all the other programmers use. They're building the smart pointers, the memory allocators, the IO libraries, and the build systems. It's imperative (to them) that their good decisions don't get snowed under the mountain of application code that the more mediocre programmers are going to be producing by the truckload. So it's important to have powerful encapsulation, compile-time checks, and metaprogramming capabilities. Doesn't matter how safe by default or how slow it all is, because the elite add guarantees themselves through the abstractions they write, and don't have to compile a full application very much, if ever.

Re: Assorted Thoughts on Zig and Rust

#269
post #83

Earlier quoted context omitted.

(By the way, Hacker News doesn't support markdown; indent your code by two spaces, rather than using fences. https://news.ycombinator.com/formatdoc ) Just a few small things: > This is a huge one for me, and I really don't understand why Rust didn't jump on this earlier. Doing this well is not easy. Exposing a full language at compile time isn't a difficult feature, but doing compile-time execution in a sound, safe w…

> Doing this well is not easy Does this also apply to the in-language build system? Given both Rust and Zig's ergonomics, it just seems so brilliantly simple (at least in hindsight) to let the build system be a library. Is it just coincidence that I've only heard of this approach for zig and Jonathan Blow's language, or is there a technical reason this is more difficult than it seems?

> I've only heard of this approach for zig and Jonathan Blow's language

It's the same approach used by nix and guix. Nix is moderately successful. I'm typing this on a laptop running nixos :)

https://nixos.org/

https://guix.gnu.org/

If you're interested in this sort of thing, this is an excellent paper on build system design, although it focuses more on the properties of the build graph than on how the graph is constructed:

https://www.microsoft.com/en-us/research/uploads/prod/2018/0...

Re: Assorted Thoughts on Zig and Rust

#270
post #217

my ears pricked up at the mention of gtk apps for the pinephone; i was planning on exploring rust and D to do precisely that. will definitely add zig to the mix now.

Here's how I set up the cross-compile in zig - https://scattered-thoughts.net/writing/pinephone-first-steps...

That only covers gl/sdl but I think gtk worked with that method too.

Post reply on HN