Live data from Hacker News

Thoughts on Go vs. Rust vs. Zig

sinclairtarget.com

261–270 of 599 posts

Re: Thoughts on Go vs. Rust vs. Zig

#261
post #214
post #29

> In Rust, creating a mutable global variable is so hard that there are long forum discussions on how to do it. In Zig, you can just create one, no problem. Well, no, creating a mutable global variable is trivial in Rust, it just requires either `unsafe` or using a smart pointer that provides synchronization. That's because Rust programs are re-entrant by default, because Rust provides compile-time thread-safety. If…

> [...] is trivial in Rust [...] it just requires [...] This is a tombstone-quality statement. It's the same framing people tossed around about C++ and Perl and Haskell (also Prolog back in the day). And it's true, insofar as it goes. But languages where "trivial" things "just require" rapidly become "not so trivial" in the aggregate. And Rust has jumped that particular shark. It will never be trivial, period.

It just requires unsafe. One concept, and then you can make a globally mutable variable.

And it's a good concept, because it makes people feel a bit uncomfortable to type the word "unsafe", and they question whether a globally mutable variable is in fact what they want. Which is great! Because this is saving every future user of that software from concurrency bugs related to that globally mutable variable, including ones that aren't even preserved in the software now but that might get introduced by a later developer who isn't thinking about the implications of that global unsafe!

Re: Thoughts on Go vs. Rust vs. Zig

#262
post #245

The last paragraph captures the essence that all the PL theory arguments do not. "Zig has a fun, subversive feel to it". It gives you a better tool than C to apply your amazing human skills, freely, whereas both Rust and Go are fundamentally sceptical about you.

Self-aware people are mindful about what "future them" might do in various scenarios, and they plan ahead to tamp down their worse tendencies. I don't keep a raspberry cheesecake in my fridge, even though that would maximize a certain kind of freedom (the ability to eat cheesecake whenever I want). I much prefer the freedom that comes with not being tempted, as it leads to better outcomes on things I really care abou…

> Random anecdote: I still have a fond memory of a glorious realization in Haskell after a colleague told me "if you design your data types right, the program just falls into place".

There's a similar quote from The Mythical Man Month [0, page 102]:

> Show me your flowchart and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won't usually need your flowcharts; they’ll be obvious.

And a somewhat related one from Linus [1]:

> I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships.

[0]: https://www.cs.cmu.edu/afs/cs/academic/class/15712-s19/www/p...

[1]: https://lwn.net/Articles/193245/

Re: Thoughts on Go vs. Rust vs. Zig

#263
post #182

Earlier quoted context omitted.

If we can produce a substantial volume of software that can cope with allocation failures then the idea of using something than overcommit as the default becomes feasible. It's not a stretch to imagine that a different namespace might want different semantics e.g. to allow a container to opt out of overcommit. It is hard to justify the effort required to enable this unless it'll be useful for more than a tiny handful…

> If we can produce a substantial volume of software that can cope with allocation failures then the idea of using something than overcommit as the default becomes feasible. Except this won't happen, because "cope with allocation failure" is not something that 99.9% of programs could even hope to do. Let's say that you're writing a program that allocates. You allocate, and check the result. It's a failure. What do yo…

Have you honestly thought about how you could handle the situation better than an crash?

For example, you could finish writing data into files before exiting gracefully with an error. You could (carefully) output to stderr. You could close remote connections. You could terminate the current transaction and return an error code. Etc.

Most programs are still going to terminate eventually, but they can do that a lot more usefully than a segfault from some instruction at a randomized address.

Re: Thoughts on Go vs. Rust vs. Zig

#264

Earlier quoted context omitted.

Which is why I said "allocate and pin ". POSIX systems have mlock()/mlockall() to prefault allocated memory and prevent it from being paged out.

Random curious person here: does mlock() itself cause the pre-fault? Or do you have to scribble over that memory yourself, too? (I understand that mlock prevents paging-out, but in my mind that's a separate concern from pre-faulting?)

FreeBSD and OpenBSD explicitly mention the prefaulting behavior in the mlock(2) manpage. The Linux manpage alludes to it in that you have to explicitly pass the MLOCK_ONFAULT flag to the mlock2() variant of the syscall in order to disable the prefaulting behavior.

Re: Thoughts on Go vs. Rust vs. Zig

#265
post #29

> In Rust, creating a mutable global variable is so hard that there are long forum discussions on how to do it. In Zig, you can just create one, no problem. Well, no, creating a mutable global variable is trivial in Rust, it just requires either `unsafe` or using a smart pointer that provides synchronization. That's because Rust programs are re-entrant by default, because Rust provides compile-time thread-safety. If…

[deleted]

Re: Thoughts on Go vs. Rust vs. Zig

#266
post #214
post #29

> In Rust, creating a mutable global variable is so hard that there are long forum discussions on how to do it. In Zig, you can just create one, no problem. Well, no, creating a mutable global variable is trivial in Rust, it just requires either `unsafe` or using a smart pointer that provides synchronization. That's because Rust programs are re-entrant by default, because Rust provides compile-time thread-safety. If…

> [...] is trivial in Rust [...] it just requires [...] This is a tombstone-quality statement. It's the same framing people tossed around about C++ and Perl and Haskell (also Prolog back in the day). And it's true, insofar as it goes. But languages where "trivial" things "just require" rapidly become "not so trivial" in the aggregate. And Rust has jumped that particular shark. It will never be trivial, period.

A language that makes making a global mutable variable feel like making any other binding is a anti-pattern and something I'm glad Rust doesn't try to pretend is the same thing.

If you treat shared state like owned state, you're in for a bad time.

Re: Thoughts on Go vs. Rust vs. Zig

#267

Earlier quoted context omitted.

I disagree. I've been writing heavy Rust for 5 years, and there are many tasks for which what you say is true. The problem is Rust is a low level language, so there is often ceremony you have to go through, even if it doesn't give you value. Simple lifetimes aren't too bad, but between that and trait bounds on some one else traits that have 6 or 7 associated types, it can get hairy FAST. Then consider a design that w…

> The problem is Rust is a low level language so there is often ceremony you have to go through, even if it doesn't give you value. As is C++ which I compared it to, where there is even more boilerplate for similar tasks. I spent so much time working with C++ just integrating disparate build systems in languages like Make and CMake which just evaporates to nothing in Rust. And that's before I even get to writing my c…

> I don't find that to be the case. It may be slower for a month or two while you learn how to work with the borrow checker, but after the adjustment period, the ideas flow just as quickly as any other language.

I was responding to "as any other language". Compared to C++, yes, I can see how iteration would faster. Compared to C#/Go/Python/etc., no, Rust is a bit slower to iterate for some things due to need to provide low level details sometimes.

Re: Thoughts on Go vs. Rust vs. Zig

#268
post #214

Earlier quoted context omitted.

> [...] is trivial in Rust [...] it just requires [...] This is a tombstone-quality statement. It's the same framing people tossed around about C++ and Perl and Haskell (also Prolog back in the day). And it's true, insofar as it goes. But languages where "trivial" things "just require" rapidly become "not so trivial" in the aggregate. And Rust has jumped that particular shark. It will never be trivial, period.

He’s talking about adding a keyword. That is all. I’d call that trivial.

Except really the invocation of `unsafe` should indicate maybe you actually don't know what you're doing and there might be a safe abstraction like a mutex or something which does what you need.

Re: Thoughts on Go vs. Rust vs. Zig

#269

Earlier quoted context omitted.

> Debugging means grepping that string in the codebase, and praying that it's unique. This really isn't an issue in practice. The only case where an error wouldn't uniquely identify its call stack is if you were to use the exact same context string within the same function (and also your callees did the same). I've never encountered such a case. > You are also not forced to add context Yes, but in my experience Go de…

The go stdlib notoriously returns errors without wrapping. I think it has been shifting towards more wrapping more often, but still. err1 := foo() err2 := bar() if err1 != nil || err2 != nil { return err1 // if only err2 failed, returns nil! } ``` func process() error { err := foo() if err != nil { return err } if something { result, err := bar() // new err shadows outer err if err != nil { return err } use(result) }…

Now all you have to do is get a Go programmer to write code like this:

    if somethingElse {
        err := baz()  
        log.Println(err)
    }
Good luck!

As for your first example,

    // if only err2 failed, returns nil!
Yes, that's an accurate description of what the code you wrote does. Like, what? Whatever point you're trying to make still hinges on somebody writing code like that, and nobody who writes Go would.

Now, can this result in bugs in real life? Sure, and it has. Is it a big deal to get a bug once in a blue moon due to this? No, not really.

Re: Thoughts on Go vs. Rust vs. Zig

#270
post #133

Earlier quoted context omitted.

This just skips the: > First, if you aren't writing device drivers/kernels or something very low level there is a high probability your program will have zero unsafe usages in it. from the original comment. Meanwhile all C code is implicitly “unsafe”. Rust at least makes it explicit! But even if you ignore memory safety issues bypassed by unsafe, Rust forces you to handle errors, it doesn’t let you blow up on null po…

Isn’t rust proffered up as a systems language? One that begged to be accepted into the Linux kernel? Don’t device drivers live in the Linux kernel tree? So, unsafe code is generally approved in device driver code? Why not just use C at that point?

I am quite certain that someone who has been on HN as long as you have is capable of understanding the difference between 0% compiler-enforced memory safety in a language with very weak type safety guarantees and 95%+ of code regions even in the worst case of low-level driver code that performs DMA with strong type safety guarantees.
Post reply on HN