Hacker News new | ask | show | jobs
by jvanderbot 605 days ago
"Rust" really just means "Not javascript" as a recurring pattern in these articles.
2 comments

Not exactly. It wouldn't help if you moved your JavaScript to Python or Ruby or PHP... and anyway it's not really feasible from an FFI perspective to move it to anything other than Rust or C/C++ or maybe Zig. There's no good reason to pick C/C++ over Rust in most of these cases...

So "Rust" means "Not JavaScript, and also a bunch of other constraints that mean that Rust is pretty much the only sensible choice."

> It wouldn't help if you moved your JavaScript to Python or Ruby or PHP...

Hum, no. The point is exactly that it would help a great deal if you moved to Python or Ruby or PHP.

Of course, Rust will give you even better memory efficiency. But Javascript is a particularly bad option there, and almost anything else would be an improvement. ("Almost", because if you push it enough and move to something like MathLab, you'll get worse results.)

If moving from JS to CPython would help, it might help memory consumption, because JITs generally trade speed for increased memory. But then you'd get slower execution, because CPython is slower than the JS engines we tend to use. PyPy might generally track JS on performance (big, BIG "it depends" because the speed profile of JITs are crazy complicated, one of my least favorite things about them) but then you're back to trading memory for speed, so it's probably net-net a sideways move.

Also, I don't know what Node is doing exactly, but if you take a lot of these dynamic languages and just fork them into multiple processes, which they still largely need to do to effectively use all the CPUs, you will generally see high per-process memory consumption just like Node. Any memory page that has a reference counter in it that is used by your code ends up Copied-On-Write in practice by every process in the steady state because all you need to do to end up copying the page is looking at any one reference it happens to contain in such a language. At least in my experience memory sharing gains were always minimal to effectively zero in such cases.

> But then you'd get slower execution, because CPython is slower than the JS engines we tend to use

I have not found this to be generally true. It depends heavily on whether your code is limited by pure high level language code[1] and culture makes comparisons harder if you’re not just switching languages but also abstraction models and a big stack of optimizations. In theory Java beats Python but in practice I’ve seen multiple times where a Java program was replaced by Python seeing whole number multiple improvements in performance and reductions in memory consumption because what was really happening is that a bunch of super complicated, optimization-resistant Java framework code was being replaced with much simpler code which was easier to optimize. Node is closer to that side of Java culturally, I think in both cases because people reacted to the limited language functionality by building tons of abstractions which are still there even after the languages improved so even though it’s possible to do much better a lot of programmers are still pushing around a lot of code with 2000s-era workarounds buried in the middle.

1. I’m thinking of someone I saw spend months trying to beat Python in Go and eking out a 10% edge because the bulk of the work devolved to stdlib C code.

I cite CPython specifically as CPython both to indicate that I mean that specific interpreter, and that I mean Python code, not Python driving other languages.

While I fully believe that a Python program with a superior O()-complexity class can beat Java (or, indeed, any language), and that a simpler Python program can hypothetically beat a Java program that is just too complicated, it would also be the case that taking that faster Python program and then porting that into Java would then see order of magnitude+ speed increases. Python is slow. When comparing languages I generally add the caveat "with some non-zero and comparable amount of time dedicated to optimization" to try to build a reasonable comparison, because most programs that have had no effort done on optimization at all will have their performance dominated by something stupid that the programmer didn't even realize they wrote.

The speed increases aren't relevant if the old Java was "too slow" and the new Python is "fast enough". Every program I've ever written could be made faster... but they're all fast enough now.

Pure Python with some non-trivial optimization effort can not beat a Java program with some non-trivial optimization effort, and that's before the Java code starts using multiple CPUs, if the problem is amenable to that.

This is not cheerleading, dumping on Python, or promoting Java, as if anything my personal biases are in fact the other way (tbh I don't particularly like either at this point but I'd much rather be using Python). This is just engineering stuff that good engineers should know: https://jerf.org/iri/post/2024/not_about_python/

I’m not saying that Java or even V8 shouldn’t be able to beat Python but rather that in many cases the optimizations needed to beat it are to a first approximation saying “stop using Spring/NextJS/etc.” and never happen. The gap between potential and actual speed has been quite frustrating to see expanding over the years.
"This Post Is Not About Python" seems to say the fans are acting irrationally by letting their political brain take over. Failure to calmly evaluate the downsides of their favorite options because they see them as attacks on the target of their fandom is a mistake that only hurts them. I think this understates the fans' case. When they see criticism of their favorite platform as an attack, it is because it is an attack in the war over network effects. Losing this war doesn't just deprive your platform of the benefits of popularity; it actively harms it by diverting shared resources.

I'll quote "Technology Holy Wars are Coordination Problems": [1]

> The enduring phenomenon of holy wars in computing, such as the bitterness around the prolonged Python 2 to Python 3 migration, is not due to mere pettiness or love of conflict, but because they are a coordination problem: the problem is not getting everyone to make a good decision, but making the same decision.

I agree that you can make better software engineering decisions if you avoid thinking like a fan and that a poor choice of language can hinder a project from the start. In light of what is at stake, though, "engineers should never be fans" is an unrealistic call for peace. It reminds me of this dialogue: [2]

> There’s a passage in the Principia Discordia where Malaclypse complains to the Goddess about the evils of human society. “Everyone is hurting each other, the planet is rampant with injustices, whole societies plunder groups of their own people, mothers imprison sons, children perish while brothers war.”

> The Goddess answers: “What is the matter with that, if it’s what you want to do?”

> Malaclypse: “But nobody wants it! Everybody hates it!”

> Goddess: “Oh. Well, then stop.”

[1] https://gwern.net/holy-war

[2] https://slatestarcodex.com/2014/07/30/meditations-on-moloch/

It depends, of course, on what you're doing. Re-using the toy web API in the article, I expect Python would be significantly faster. The QR code library you'd end up using in Python is probably written in C, and the web-serving portion should have comparable performance characteristics as you'd get with nodejs.

My guess is that if you were to rewrite this same app in straight Python (no Rust at all), it would probably already give you "Tier 3" performance.

But sure, I bet there are a bunch of use cases where nodejs would be faster than Python.

This seems a bit unfair to JavaScript. There’s a lot of optimizations made to the language and its runtimes that have made a more than viable choice for server side applications over the years. The JavaScript that started as a Webbrowser client side language is very different from the ECMAScript that we have today. Depending on its usage it can also be one of the fastest, only regularly eclipsed by rust[1]. So no, JavaScript really isn’t a bad option for server side applications at all.

[1] https://www.techempower.com/benchmarks/#hw=ph&test=composite...

Not sure about Python or Ruby, but PHP is definitely MUCH faster. It helps a lot when a ton of the code is in C modules (which I guess is maybe the case for Python too?)
> There's no good reason to pick C/C++ over Rust in most of these cases...

What leads you to believe in that?

Because except in rare cases Rust can do everything C++ can do with basically the same performance profile, but it does it with modern tooling and without the security, reliability and productivity issues associated with C++'s pervasive Undefined Behaviour.

There are some cases where C++ makes sense:

* You have a large existing C++ codebase you need to talk to via a large API surface (C++/Rust FFI is not great)

* You have a C++ library that's core to your project and doesn't have a good Rust alternative (i.e. Qt)

* You don't like learning (and are therefore in completely the wrong industry!)

The constant stream of CVEs caused by even experts failing to use those languages correctly on the one side, and the much better developer experience on the other. C++ isn’t horrible but it’s harder to use, harder to find good developers, and there are relatively few cases where there’s something easier to do in C++ than Rust which would warrant picking it. In most cases, it’ll be both faster and safer if you use a modern language with good tooling instead and take advantage of the easy C bindings if there’s a particular library you need.
> The constant stream of CVEs (...)

It's a function of popularity and widespread use. The only languages that do not feature CVEs are the ones that are not used.

Eve Rust started to feature in CVEs, including memory safety problems in it's standard library. Somehow that fact is omitted from these discussions.

> (...) even experts failing to use those languages correctly (...)

I couldn't help noticing you felt the need to resort to weasel words like "correctly" to add color to an unsubstantiated personal assertion.

What's the best example you can come up with to support your opinion?

> C++ isn’t horrible but it’s harder to use, harder to find good developers (...)

This personal assertion is comical, as recruiters are systematically targeting C++ developers for Rust positions, and Rust is notoriously bad for newbies to onboard onto.

I'd prefer these debates were kept at an objective and substantiated level, but it seems that's too much to ask. It seems it's easier to throw unsubstantiated claims around and wait to see if half the bullshit sticks.

> Somehow that fact is omitted from these discussions.

Oh, please. Nobody is saying that Rust is perfect, only that the defect rate in normal usage is considerably lower and tend to be concentrated in areas like “unsafe” blocks rather than spread randomly around the code base.

> I couldn't help noticing you felt the need to resort to weasel words like "correctly" to add color to an unsubstantiated personal assertion. … This personal assertion is comical, as recruiters are systematically targeting C++ developers for Rust positions, and Rust is notoriously bad for newbies to onboard onto.

“Correctly” isn’t a weasel word, especially not in the context of describing how a program functions. I was referring to the common excuse that has cropped up over decades where language proponents try to blame problems on the user rather than acknowledging that certain features are hard to use safely.

I’ve been hearing people say that C/C++ are fine and you just need better programmers since the 90s, which has not been an effective strategy in reducing the number of security vulnerabilities. My comment about easier to learn was written in the context of reaching the level needed to reliably write safe code, not just producing a compilable program which doesn’t immediately crash since even large, elite teams with enormous resources struggle with memory safety bugs in large C/C++ code bases.

For example, Android reports halving their code rollback rate and a significant reduction in the number of vulnerabilities by switching to memory-safe languages. Clearly relying on programmer vigilance and testing was not as effective as picking tools which made certain classes of error much harder.

https://security.googleblog.com/2024/09/eliminating-memory-s...

> Oh, please. Nobody is saying that Rust is perfect (...)

This is the kind of fallacies that dominate Rust fanboy's discourse.

You start off by mindlessly commenting on "constant stream of CVEs", but when you're faced with the reality that Rust also piles up CVEs then you start to try to move goalposts around. Odd how you switched from CVE talk to vague allusions of "perfection", as if now CVEs don't matter.

That's the problem with your type of fanaticism: you stop makint technical claims and instead resort to sweeping baseless accusations,as if that was a positive trait on a language and it's community.

> “Correctly” isn’t a weasel word, especially not in the context of describing how a program functions.

It is. There is no way around it.

> My comment about easier to learn was written in the context of reaching the level needed to reliably write safe code (...)

Again with the goalpost-moving/weasel word combo.

Rust is notoriously unfriendly to beginners and imposes an unparalleled learning curve. Around a quarter of new developers outright give up and quit over how unusable it is to them. This is acknowledged by the Rust community itself as demonstrated by the last annual Rust survey. There is no way around it. I don't know why anyone would try to waste time handwaving over this.

> For example, Android reports halving their code rollback rate and a significant reduction in the number of vulnerabilities by (...)

Here's the problem with this sort of specious reasoning. You are cherry-picking an example of how a project invested heavily in memory safety and therefore ended up lowering vulnerabilities. You ignore how much work was invested into processes and prioritizing specific types of problems. You instead decide to ignore everything and anything, and opt to go the simplistic path of pretending that the only step required to achieve these gains is onboarding a magical tool, as if nothing else was a factor.

Do you understand how this blend of cargo cult mentality is silly and unproductive?

I get it that you feel the need to promote a tool you like. That's fine. But if you had a case you wouldn't feel compelled to frame all your arguments on artificial scenarios you try to pin on all other tools, would you?

I’m not a big believer in absolutes like that, but unless a person is already proficient in C or C++, or there’s an existing C++ library, etc., I find it hard to justify using those over Rust. Rust has great tooling, good cross compilation support, good quality standard library and very good 3rd party ecosystem.

Also, it has so few footguns compared to C or C++ even modestly experienced developers can safely use it.

A host of a prominent C++ podcast expressed more or less this sentiment recently (on an ep within the last year). He was being a little bit "devil's advocate", and not suggesting stopping working with C++ altogether. But he could see most use cases of C++ being well satisfied by Rust, and with more ergonomic features like Cargo making the overall experience less of a chore.
It's also frankly kinda like comparing apples and oranges as a language. JavaScript (and many of the "bad performance" high level languages minus Rails; Rails is bad and should be avoided for projects as much as possible unless you have lots of legacy cruft) are also heavily designed around rapid iteration. Rust is however very much not capable of rapid iteration, the borrow checker will fight you heavily every step of the way to the point where it demands constant refactors.

Basically the best place where Rust can work is one where all variables, all requirements and all edgecases are known ahead of time or cases where manual memory safety is a necessity vis-a-vis accepting a minor performance hike from things like the garbage collector. This works well in some spaces (notably; systems programming, embedded and Browser Engines and I wouldn't consider the latter a valid target), but webserver development is probably one of the furthest places where you are looking for Rust.

I found this to be untrue after I spent a little energy learning to think about problems in rust.

In a lot of languages you're working with a hammer and nail (metaphorically speaking) and when you move to a different language its just a slightly different hammer and nail. Rust is a screwdriver and screw though, and once I stopped trying to pound the screw in with the screwdriver, but rather use the one to turn the other, it was a lot easier. Greenfield projects with a lot of iteration are just as fast as doing it in python (although a bit more front-loaded rather than debugging), working new features into existing code - same thing.

I have often thought that programmers can actually just choose to make Rust easy by using a cyclic garbage collector such as Samsara. [1] If cyclic GC in Rust works as well as I think it can, it should be the best option for the majority of high level projects that need fast development with a trade-off of slightly lower efficiency. I suspect we'll see a "hockey stick" adoption curve once everyone figures this out.

[1] https://github.com/chc4/samsara

I am still waiting for a scripting language to be bolted on top of Rust. Something that will silently Box all the values so the programmer does not have to think about the Rust specifics, but can still lean on all of the Rust machinery and libraries. If performance/correctness becomes a problem, the scripting layer could be replaced piecemeal with real Rust.
Perhaps you mean to say that you're waiting for a new scripting language to be created that's designed to be "almost Rust." That could be interesting! OTOH, the bindings for existing languages have matured significantly:

  - https://pyo3.rs/
  - https://github.com/neon-bindings/neon
  - https://github.com/mre/rust-language-bindings
I definitely am thinking of something more Rust-forward. As Rusty as possible without having to worry about lifetimes, the borrow checker, whatever. Huge performance hit is acceptable, so long as it remains trivial to intermix the Rust+scripting code. Something that gives a smooth on-ramp to push the heavy bits into pure Rust if required. The Python+C strategy in a more integrated package.
> As Rusty as possible without having to worry about lifetimes, the borrow checker

It's Ocaml

You're very much describing the powershell -> .Net -> C# path so would be curious to hear your take there. There's also the mad lad support rust in .net https://github.com/FractalFir/rustc_codegen_clr/
And then we would’ve come full circle.

Beautiful

The world is mad. After a decade of this, I give up. The cycles never end.
I know. We're all just rediscovering Lisp in our own way.

... And yet the fact that most of us know we're reinventing Lisp, and still doing it anyway, says something. I guess it says that we're just trying to get our jobs done.

This is what async/await rust programmers need

They are comfortable with runtimes

> Rust is however very much not capable of rapid iteration, the borrow checker will fight you heavily every step of the way to the point where it demands constant refactors.

Misconception.

You will encounter the borrow checker almost never when writing backend web code in Rust. You only encounter it the first time when you're learning how to write backend code in Rust. Once you've gotten used to it, you will literally never hit it.

Sometimes when I write super advanced endpoints that mutate global state or leverage worker threads I'll encounter it. But I'm intentionally doing stuff I could never do in Python or Javascript. Stuff like tabulating running statistics on health check information, batching up information to send to analytics services, maintaining in-memory caches that talk to other workers, etc.

To put this another way: the Rust borrow checker attempts to tie memory lifetime to stack frames.

This tends to work well for most crud api servers, since you allocate “context, request, and response” data at the start of the handler function, and deallocate at the end. Most helper data can also be tied to the request lifecycle. And data is mainly isolated per-request. Meaning there isn’t much data sharing across multiple request.

This means that the borrow checker “just works”, and you probably won’t even need lifetime annotations or even any special instructions for the borrow checkers. It’s the idealized use case the borrow checker was designed for.

This is also the property which most GC languages like Java, Go, and C# exploit with generational garbage collectors. The reason it “works” in Java happens to be the same reason it works in Rust.

If your server does need some shared in-memory data, you can start by just handing out copies. If you truly need something more complicated, and we are talking about less than 10% of crud api servers here, then you need to know a thing or two about the borrow checker.

I’m not saying to rewrite web servers in Rust, or even advocating for it as a language. I’m just pointing out that a crud api server is the idealized use case for a borrow checker.

Incredibly well said. This is precisely what makes it work so well.

The language never set out to solve this problem. It wasn't an intentional design goal. The language design and problem space just happen to overlap more or less perfectly.

Complete serendipity.

> the borrow checker will fight you heavily every step of the way to the point where it demands constant refactors.

No

Once you learn to surrender to the borrow checker it becomes friend, not foe

You must submit

You've described Rust's niche circumspectly: Systems, which have strict requirements and are fragile minefields.

The performance benefits of Rust were supposed to be a non-penalty: "Look, you can please please use this where you'd use C or C++ I promise it won't impact your performance!" Performance and GC overhead was the rejection de jure of every other C replacement.

But here we are: All friends are javascript front-enders-turned-backenders and are wondering if they should pick up Rust. It fits into a pattern of "new shiny" but it's good, don't get me wrong, if everyone experiences compiled languages and starts writing their headless code in sensible languages.

Repeating myself, but I'm just wondering why not Go? Why now?

>Rust is however very much not capable of rapid iteration, the borrow checker will fight you heavily every step of the way to the point where it demands constant refactors.

If you have sufficient experience, that's not really the case. Certainly compared to "comparable" languages like C++ where that time fighting the borrow checker might instead have been spent chasing random crashes.

I have written both professionally for long enough to say that there's not real comparable advantage to either. You trade one complexity to fight for another when refactoring or iterating.
I don't think this is very true. Certainly, you can rapidly iterate in C#, and it's so much faster it's not even close.

But, if you want a dynamically typed experience, look no further than PHP or Perl. Also significantly faster, and, if I had to bet, you could probably iterate much faster in Perl. It wouldn't be fun, but honestly, I doubt that Perl is more footgunny than JS.

Writing server API'n'co is not unknown path that needs rapid prototyping.