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

> [...] 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.





> languages where "trivial" things "just require" rapidly become "not so trivial" in the aggregate

Sure. And in C and Zig, it's "trivial" to make a global mutable variable, it "just requires" you to flawlessly uphold memory access invariants manually across all possible concurrent states of your program.

Stop beating around the bush. Rust is just easier than nearly any other language for writing concurrent programs, and it's not even close (though obligatory shout out to Erlang).


This is a miscommunication between the values of “shipping” which optimizes for fastest time to delivery and “correctness” which optimizes for the quality of the code.

Rust makes it easy to write correct software quickly, but it’s slower for writing incorrect software that still works for an MVP. You can get away with writing incorrect concurrent programs in other languages… for a while. And sometimes that’s what business requires.

I actually wish “rewrite in Rust” was a more significant target in the Rust space. Acknowledging that while Rust is not great for prototyping, the correctness/performance advantages it provides justifies a rewrite for the long-term maintenance of software—provided that the tools exist to ease that migration.


Lately rust is my primary language, and I couldn't agree more with this.

I've taken to using typescript for prototyping - since its fast (enough), and its trivial to run both on the server (via bun) or in a browser. The type system is similar enough to rust that swapping back and forth is pretty easy. And there's a great package ecosystem.

I'll get something working, iterate on the design, maybe go through a few rewrites and when I'm happy enough with the network protocol / UI / data layout, pull out rust, port everything across and optimize.

Its easier than you think to port code like this. Our intuition is all messed up when it comes to moving code between languages because we look at a big project and think of how long it took to write that in the first place. But rewriting code from imperative language A to B is a relatively mechanical process. Its much faster than you think. I'm surprised it doesn't happen more often.


I'm in a similar place, but my stack is Python->Go

With Python I can easily iterate on solutions, observe them as they change, use the REPL to debug things and in general just write bad code just to get it working. I do try to add type annotations etc and not go full "yolo Javascript everything is an object" -style :)

But in the end running Python code on someone else's computer is a pain in the ass, so when I'm done I usually use an LLM to rewrite the whole thing in Go, which in most cases gives me a nice speedup and more importantly I get a single executable I can just copy around and run.

In a few cases the solution requires a Python library that doesn't have a Go equivalent I just stick with the Python one and shove it in a container or something for distribution.


I'm in the camp of "If your target is Go, then prototype in Go." I don't bother with the intermediate step. Go is already so very close to being a dynamic language that I don't get the point. Just write "bad" Go to prototype quickly. Skip the error checks. Panic for fun. Write long functions. Make giant structs. Don't worry about memory.

You mentioned running someone else's python is painful, and it most certainly is. No other language have I dealt with more of the "Well, it works on my machine" excuse, after being passed done the world's worst code from a "data scientist". Then the "well, use virtual environments"... Oh, you didn't provide that. What version are you using? What libraries did you manually copy into your project? I abhor the language/runtime. Since most of us don't work in isolation, I find the intermediate prototype in another language for Go a waste of time and resources.

Now... I do support an argument for "we prototype in X because we do not run X in production". That means that prototype code will not be part of our releases. Let someone iterate quickly in a sandbox, but they can't copy/paste that stuff into the main product.

Just a stupid rant. Sorry. I'm unemployed. Career is dead. So, I shouldn't even hit "reply"... but I will.


I second your experience with Python. I've been coding in Python for 10+ years. When I get passed down some 'data scientist' code, I often it breaks.

With Rust, it was amazing - it was a pain to get it compiled and get past the restrictions (coming from a Python coder) - the code just ran without a hitch, and it was fast, never even tried to optimize it.

As a Python 'old-timer' , I also am not impressed with all the gratuitous fake typing , and especially Pydantic. Pydantic feels so un-pythonic, they're trying to make it like Go or Rust, but its falling flat, at least for me.


Is there a good resource on how to get better at python prototyping?

The typing system makes it somewhat slow for me and I am faster prototyping in Go then in Python, despite that I am writing more Python code. And yes I use type annotations everywhere, ideally even using pydantic.

I tend to use it a lot for data analytics and exploration but I do this now in nushell which holds up very well for this kind of tasks.


Just do it I guess? :D

When I'm receiving some random JSON from an API, it's so much easier to drop into a Python REPL and just wander around the structure and figure out what's where. I don't need to have a defined struct with annotations for the data to parse it like in Go.

In the first phase I don't bother with any linters or type annotations, I just need the skeleton of something that works end to end. A proof of concept if you will.

Then it's just iterating with Python, figuring out what comes in and what goes out and finalising the format.


Thank you, but the JSON API stuff is exactly what i am using nushell for at the moment. Makes it trivial to navigate large datasets.

For me it's pretty hard to work without type annotations, it just slows me down.

Don't get me wrong, I really like python for what it is, I simply missing out on the fast prototype stuff that everyone else is capable of.


> Rust makes it easy to write correct software quickly, but it’s slower for writing incorrect software that still works for an MVP.

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.

Additionally, being able to tell at a glance what sort of data functions require and return saves a ton of reading and thinking about libraries and even code I wrote myself last week. And the benefits of Cargo in quickly building complex projects cannot be overstated.

All that considered, I find Rust to be quite a bit faster to write software in than C++, which is probably it's closest competitor in terms of capabilities. This can be seen at a macro scale in how quickly the Rust library ecosystem has grown.


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 would normally have self referential structs, or uses heavy async with pinning, async cancellation, etc. etc.

I do agree that OFTEN you can get good velocity, but there IS a cost to any large scale program written in Rust. I think it is worth it (at least for me, on my personal time), but I can see where a business might find differently for many types of programs.


> 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 code.

> I do agree that OFTEN you can get good velocity, but there IS a cost to any large scale program written in Rust.

I'm not saying there's no cost. I'm saying that in my experience (about 4 years into writing decently sized Rust projects now, 20+ years with C/C++) the cost is lower than C++. C++ is one of the worst offenders in this regard, as just about any other language is easier and faster to write software in, but also less capable for odd situations like embedded, so that's not a very high bar. The magical part is that Rust seems just as capable as C++ with a somewhat lower cost than C++. I find that cost with Rust often approaches languages like Python when I can just import a library and go. But Python doesn't let me dip down to the lower level when I need to, whereas C++ and Rust do. Of the languages which let me do that, Rust is faster for me to work in, no contest.

So it seems like we agree. Rust often approaches the productivity of other languages (and I'd say surpasses some), but doesn't hide the complexity from you when you need to deal with it.


> 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.


> Rust is a bit slower to iterate for some things due to need to provide low level details sometimes.

Sometimes specific tasks in Rust require a little extra effort - like interacting with the file picker from WASM required me to write an async function. In embedded sometimes I need to specify an allocator or executor. Sometimes I need to wrap state that's used throughout the app in an Arc(Mutex()) or the like. But I find that there are things like that in all languages around the edges. Sometimes when I'm working in Python I have to dip into C/C++ to address an issue in a library linked by the runtime. Rust has never forced me to use a different language to get a task done.

I don't find the need to specify types to be a particular burden. If anything it speeds up my development by making it clearer throughout the code what I'm operating on. The only unsafe I've ever had to write was for interacting with a GL shader, and for binding to a C library, just the sort of thing it's meant for, and not really possible in those other languages without turning to C/C++. I've always managed to use existing datastructures or composites thereof, so that helps. But that's all you get in languages like C#/Go/Python/etc. as well.

The big change for me was just learning how to think about and structure my code around data lifetimes, and then I got the wonderful experience other folks talk about where as soon as the code compiles I'm about 95% certain it works in the way I expect it to. And the compiler helps me to get there.


There is a real argument to be made that quick prototyping in Rust is unintuitive compared to other languages, however it's definitely possible and does not even impact iteration speed all that much: the only cost is some extra boilerplate, without even needing to get into `unsafe` code. You don't get the out-of-the-box general tracing GC that you have in languages like Golang, Java/C# or ECMAScript, or the bignum-by-default arithmetic of Python, but pretty much every other basic facility is there, including dynamic variables (the `Any` trait).

In an ideal world, where computing software falls under the same liability laws as everything else, there is no shipping without correctness.

Unfortunately too many people accept using computers requires using broken produts, something that most people would return on the same day with other kind of goods.


> Rust makes it easy to write correct software quickly, but it’s slower for writing incorrect software that still works for an MVP

YMMV on that, but IMHO the bigger part of that is the ecosystem , especially for back-end. And by that metric, you should never use anything else than JS for prototyping.

Go will also be faster than Rust to prototype backend stuff with because most of what you need is in the standard library. But not by a large margin and you'll lose that benefit by the time you get to production.

I think most people vastly overestimate the friction added by the borrow checker once you get up to speed.


Funny that you mentioned Erlang since Actors and message passing are tricky to implent in Rust (yes, I’ve seen Tokio). There is a readon why Rust doesnt have a nice GUI library, or a nice game engine. Resources must be shared, and there is more to sharing than memory ownership.

> it "just requires" you to flawlessly uphold memory access invariants manually across all possible concurrent states of your program.

No it doesn't. Zig doesn't require you to think about concurrency at all. You can just not do concurrency.

> Stop beating around the bush. Rust is just easier than nearly any other language for writing concurrent programs

This is entirely unrelated to the problem of defining shared global state.

    var x: u64 = 10;
There. I defined shared global state without caring about writing concurrent programs.

Rust (and you) makes an assertion that all code should be able to run in a concurrent context. Code that passes that assertion may be more portable than code that does not.

What is important for you to understand is: code can be correct under a different set of assertions. If you assert that some code will not run in a concurrent environment, it can be perfectly correct to create a mutable global variable. And this assertion can be done implicitly (ie: I wrote the program knowing I'm not spawning any threads, so I know this variable will not have shared mutable access).


Rust doesn't require you to think about concurrency if you don't use it either. For global variables you just throw in a thread_local. No unsafe required.

> This is entirely unrelated to the problem of defining shared global state

In it's not. The only thing that makes having a shared global state unsafe in Rust is the fact that this “global” state is shared across threads.

If you know you want the exact same guarantees as in Zig (that is code that will work as long as you don't use multiple threads but will be UB if you do) then it's just: static mut x: u64 = 0;

The only difference between Zig and Rust being that you'll need to wrap access to the shared variable in an unsafe block (ideally with a comment explaining that it's safe as long as you do it from only one thread).

See https://doc.rust-lang.org/nightly/reference/items/static-ite...


> Rust (and you) makes an assertion that all code should be able to run in a concurrent context.

It really doesn't. Rust's standard library does to an extent, because rust's standard library gives you ways to run code in concurrent contexts. Even then it supports non-concurrent primitives like thread locals and state that can't be transferred or shared between threads and takes advantage of that fact. Rust the language would be perfectly happy for you to define a standard library that just only supports the single threaded primitives.

You know what's not (generally) safe in a single threaded context? Mutable global variables. I mean it's fine for an int so long as you don't have safe ways to get pointer types to it that guarantee unique access (oops, rust does. And it's really nice for local reasoning about code even in single threaded contexts - I wouldn't want to give them up). But as soon as you have anything interesting, like a vector, you get invalidation issues where you can get references to memory it points to that you can then free while you're still holding the reference and now you've got a use after free and are corrupting random memory.

Rust has a bunch of abstractions around the safe patterns though. Like you can have a `Cell<u64>` instead of a `u64` and stick that in a thread local and access it basically like a u64 (both reading and writing), except you can't get those pointers that guarantee nothing is aliasing them to it. And a `Cell<Vec<u64>>` won't let you get references to the elements of the vector inside of it at all. Or a `RefCell<_>` which is like a RwLock except it can't be shared between threads, is faster, and just crashes instead of blocking because blocking would always result in a deadlock.


I mean I get what you are saying but part of the problem is today this will be true tomorrow some poor chap maintaining the code will forget/misunderstand the intent and hello undefined behavior.

I am glad that there is such comment among countless that try their best to convince that Rust way is just the best way to do stuff, whatever the context.

But no, clearly there is no cult build around Rust, and everyone that suggest otherwise is dishonest.


> it "just requires" you to flawlessly uphold memory access invariants manually across all possible concurrent states of your program.

Which, for certain kinds of programs, is trivially simple for e.g. "set value once during early initialization, then only read it". No, it's not thread-local. And even for "okay, maybe atomically update it once in a blue moon from one specific place in code" scenario is pretty easy to do locklessly.


Sure, and those use cases are just as easily supported by Rust, in a more principled manner that directly encodes the intent and resists misuse by people modifying the code later.

This is really it to me. It's like saying, "look people it's so much easier to develop and build an airplane when you don't have to adhere to any rules". Which of course is true. But I don't want to fly in any of those airplanes, even if they are designed and build by the best and brightest on earth.

I find Elixir and Erlang easier, but I'm still a neophyte with Rust, so I may feel differently in a year.

>it "just requires" you to flawlessly uphold memory access invariants manually across all possible concurrent states of your program.

The difference is it doesn't prevent you so it doesn't "just require"


Sure, it only "just requires" it if you actually care about your program working properly in the presence of concurrency. To reiterate, this is as true in Rust as it is in C or Zig, it's just that also Rust allows you to do better than the "YOLO" approach to concurrency in a way that most languages could only dream of.

Seriously, I'm begging people to try writing a program that uses ordinary threads in Rust via `std::thread::scope`, it's eye-opening how lovely thread-based concurrency is when you have modern tools at your disposal.


Is it easier than golang?

https://www.ralfj.de/blog/2025/07/24/memory-safety.html

Go is by default not thread safe. Here the author shows that by looping

    for {
        globalVar = &Ptr { val: &myval }
        globalVar = &Int { val: 42 }
     }
You can create a pointer with value 42 as the type and value are two different words and are not updated atomically

So I guess go is easier to write, but not with the same level of safety


Go is easy until one needs to write multithreaded code with heavy interactions between threads. Channels are not powerful enough to express many tasks, explicit mutexes are error prone and Context hack to support cancellation is ugly and hard to use correctly.

Rust channels implemented as a library are more powerful covering more cases and explicit low-level synchronization is memory-safe.

My only reservation is the way async was implemented in Rust with the need to poll futures. As a user of async libraries it is very ok, but when one needs to implement a custom future it complicates things.


Rust is a 99% solution to a 1% problem.

Presumably this is gray because it's a quip, but I think that's about right. So, so, so much rust is being written for applications that just don't need it. For almost everything[1] a managed runtime like Go or Java or .NET is going to be just as effectively deployed, significantly cheaper to develop and much cheaper to maintain.

And the situations where you really need a "systems programming" environment have been really at best a wash with Rust. It's mostly replacing boring middleware (c.f. the linked article). Where are the rustacean routing engines and database backends and codecs and kernels? Not in deployment anywhere, not yet. C still rules that world, even for new features.

[1] Well, everything big enough to need a typesafe high performance platform. The real "everything", to first approximation, should be in python.


> For almost everything a managed runtime like Go or Java or .NET is going to be just as effectively deployed, significantly cheaper to develop

That might be true. I personally still prefer to use a language with sum-types and exhaustive pattern matching for encoding business logic.

> and much cheaper to maintain.

[citation needed]

> Where are the rustacean routing engines and database backends and codecs and kernels? Not in deployment anywhere, not yet.

It is used at Amazon on Firecracker, S3, EC2, CloudFront, Route 53, and that's just what was publicly talked about in 2020[0].

It is used in Android, including in the Kernel[1].

It is used at Microsoft, including in the Kernel[2].

It is used extensively in Firefox, and less extensively in Chrome. JPEG XL might be reincorporated into them because there's a Rust codec in the works.

For databases, the earliest I remember is TiKV[3], which hit 1.0 back in 2018. There are others since.

> C still rules that world, even for new features.

Sure. So?

[0]: https://aws.amazon.com/blogs/opensource/why-aws-loves-rust-a...

[1]: https://security.googleblog.com/2025/11/rust-in-android-move...

[2]: https://www.thurrott.com/windows/282471/microsoft-is-rewriti...

[3]: https://github.com/tikv/tikv


It they had not messed up async it would be much better

Given the constraints I still haven’t seen an asynchronous proposal for Rust that would do things differently.

Keep in mind that one requirement is being able to create things like Embassy.

https://github.com/embassy-rs/embassy


I agree, I think they should have delayed it.

In a different universe rust still does not have async and in 5 years it might get an ocaml-style effect system.


And in that universe Rust is likely an inconsequential niche language.

If rust skipped async features I think it would not have damaged it much

Almost the entire early large scale adoption came from people writing async web services.

From 2023:

> In that regard, async/await has been phenomenally successful. Many of the most prominent sponsors of the Rust Foundation, especially those who pay developers, depend on async/await to write high performance network services in Rust as one of their primary use cases that justify their funding.

https://without.boats/blog/why-async-rust/


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!


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.


Nah, learning Rust is trivial. I've done it 3 or 4 times now.

In how many lifetimes?

lifetimes is Err. Returning to caller.

‘static

> Rust has jumped that particular shark. It will never be trivial, period.

Maybe, but the language being hard in aggregate is very different from the quoted claim that this specific thing is hard.


Well-designed programming languages should disincentivize from following a wrong practice and Rust is following the right course here.

The caveat here is that there is a complexity cost in borrowing mechanics and for a large number of applications it might not be the best option.

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.

Sure, of course. It's an aptly named keyword.



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

Search: