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

C# and Java are closer but not really on the level of Rust when it comes to performance. A better comparison would be with C++ or a similarly low-level language.

In my experience, languages like Ruby and Python are slower than languages like Javascript, which are slower than languages like C#/Java, which are slower than languages like C++/Rust, which are slower than languages like C and Fortran. Assembly isn't always the fastest approach these days, but well-placed assembly can blow C out of the water too.

The ease of use and maintainability scale in reverse in my experience, though. I wouldn't want to maintain the equivalent of a quick and dirty RoR server reimplemented in C or assembly, especially after it's grown organically for a few years. Writing Rust can be very annoying when you can't take the normal programming shortcuts because of lifetimes or the borrow checker, in a way that JIT'ed languages allow.

Everything is a scale and faster does not necessarily mean better if the code becomes unreadable.




> A better comparison would be with C++ or a similarly low-level language.

Right, but then I'd have to write C++. Shallow dismissal aside (I really do not enjoy writing C++), the bigger issue is safety: I am almost certain to write several exploitable bugs in a language like C++ were I to use it to build an internet-facing web app. The likelihood of that happening with Rust, Java, C#, or any other memory-safe language is much lower. Sure, logic errors can result in security issues too, and no language can save you from those, but that's in part the point: when it comes to the possibility of logic errors, we're in "all things being equal" territory. When it comes to memory safety, we very much are not.

So that pretty much leaves me with Rust, if I've decided that the memory footprint or performance of Java or C# isn't sufficient for my needs. (Or something like Go, but I personally do not enjoy writing Go, so I wouldn't choose it.)

> Everything is a scale and faster does not necessarily mean better if the code becomes unreadable.

True, but unreadable-over-time has not been my experience with Rust. You can write some very plain-vanilla, not-"cleverly"-optimized code in Rust, and still have great performance characteristics. If I ever have to drop into 'unsafe' in a Rust code base for something like a web app, most likely I'm doing it wrong.


Rust provides better tools to handle logic errors as well. Sum types/exhaustive pattern matching, affine typing, and mutability xor aliasing let you model many kinds of real-world logical constraints within the type system. (And not just theoretically -- the teams and projects I work on use them every day to ship software with fewer bugs than ever.)


I'd even argue that idiomatic Rust is less prone to those "logic errors" than C++ and the language design gives you fewer chances to trip over yourself.

Even the basics, nobody is calling Rust's [T]::sort_unstable without knowing it is an unstable sort. Even if you've no idea what "stability" means in this context you are cued to go find out. But in C++ that is just called "sort". Hope you don't mind that it's unstable...

[Edited because I can't remember the correct order of words apparently.]


> when it comes to the possibility of logic errors, we're in "all things being equal" territory. When it comes to memory safety, we very much are not.

Very well summed. I'll remember this exact quote. Thank you.


My goal with the project was to compare higher performance memory safe languages to Javascript in terms of memory footprint, throughput, latency, as well as the difficulty of implementation. Rust was, relatively speaking, slightly more difficult: because concurrently manipulated data needed to be explicitly wrapped in a mutex, and transforming arbitrary JSON structures (which was what one of the endpoints did) was slightly more complex than in the others. But, overall, even the endpoints that I thought might be tricky in Rust weren't really what I'd call difficult to implement, and it wasn't difficult to read either. It seemed worth the trade-off to me and I regret not having more opportunities to work with it professionally in the time since.


C and Fortran are not faster than C++, and haven't been for a long time. I've used all three languages in high-performance contexts. In practice, C++ currently produces the fastest code of high-level languages.


Because C++ doesn't restrict aliasing there are a bunch of cases where it's just unavoidably worse. The compiler is obliged to assume that if there are potentially aliasing objects of type T: T1 and T2 then mutating T1 might also mutate T2 (because it may be an alias), so therefore we must re-fetch T2.


That is more theory than reality in high-performance code, and was noted as such even back when I was in HPC. The compiler isn’t stupid and normal idiomatic high-performance code in C++ has codegen that is essentially indistinguishable from the FORTRAN in virtually all cases. It has been a couple decades and many compiler versions since anyone had to worry about this. One of the things that killed the use of FORTRAN in HPC is that it empirically did not produce code that was any faster than C++ in practice and was much more difficult to maintain. Advantage lost.

The extensive compile-time metaprogramming facilities in C++ give it unique performance advantages relative to other performance languages, and is the reason it tends to be faster in practice.


Generally, the reason C++ is so stupidly fast compared to even C is because a lot is pushed to compile-time via templates. You can avoid passing pointers, doing indirection, and you can even inline functions altogether. Flattening objects and methods to encode as much information as you can in the type at compile-time will almost always be much faster than doing dynamic redirection at runtime.

For example, compare the speed and implementation of std::sort and qsort (it's almost an order of magnitude difference in run time for big N!)


Sure, but note that unlike the aliasing overhead the C programmer can just specialise by hand to get the same results.

Also, sorting is something where algorithmic improvement makes a sizeable difference so you need to be sure you're either measuring apples vs apples or that you've decided up front what your criteria are (e.g. lazy people will use the stdlib so only test that; or nobody sorts non-integer types so I only test those)

For some inputs if you're willing to use a specialist sort the best option today is C. If you care enough to spend resources on specialising the sort for your purpose that's a real option. Or alternatively if you can't be bothered to do more than reach for the standard library of course Rust has significantly faster sort (stable and unstable) than any of the three C++ stdlibs. Or maybe you want a specialized vector sort that Intel came up with and they wrote it for C++. Hope portability wasn't an issue 'cos unsurprisingly Intel only care if it works on Intel CPUs.


> can just specialise by hand to get the same results

Sure, if you write all the code. If you're writing a library or more generic functions, you don't have that power.

And, even then, while you can do this it's going to be much more code and more prone to bugs. C++ is complex, but that complexity can often bring simplicity. I don't need to specialize for int, double, float, etc because the compiler can do it for me. And I know the implementation will be correct. If I specialize by hand, I can make mistakes.

In addition, this isn't something where C "shines". You can do the exact same thing in C++, if you want. Many templates have hand-rolled specializations for some types.

> apples vs apples

It is, they're both qsort. When every single comparison requires multiple dereferences + a function call it adds up.

> For some inputs if you're willing to use a specialist sort the best option today is C

I don't understand how. Even if this is the case, which I doubt, you could just include the C headers in a C++ application. So, C++ is equally as good of a choice + you get whatever else you want/need.

> Rust has significantly faster sort (stable and unstable) than any of the three C++ stdlibs

Maybe, but there's a new std::sort implementation in LLVM 17. Regardless, the Rust implementations are very fast for the same reason the C++ implementations are fast - encoding information in types at compile-time and aggressively inlining the comparison function. Rust has a very similar generic methodology to C++.


> It is, they're both qsort.

Oh! No, that's not a thing. What's happened there is you saw that the libc function was named qsort and you went "I am smart, I know that means Tony Hoare's Quicksort algorithm from the 1960s" but that's not what it means, it is named that way but it's only defined as an unstable sort, the libc does not promise any particular algorithm.

Over in C++ land they also don't specify the sort algorithm used but in C++ 11 they mandated that the provided function must have worst case O(n log n) performance. This is awkward for Quicksort because although Tony's algorithm is very fast on average, its worst case is O(n squared) which is very slow

Thus, conforming C++ libraries are definitely not a Quicksort. Now, conformance to the C++ ISO standard is basically a minor curiosity and nobody cares, so Clang for example just didn't bother and shipped a Quicksort anyway until relatively recently, but already we can see that we're by no means guaranteed these are "both qsort" nor that they're both anything in particular.

The thing you should do is an introspective sort or "Introsort". There are a lot of these, for some time the best general purpose algorithm was PDQsort, the Pattern Defeating Quicksort by Orson. But even though that word "Quicksort" is in there this is not just "Well it's qsort so it's the same anyway" any more than a Cayenne is the same as a road legal 911 is the same as Porsche's 963 track car.


I am skeptical about this. Optimizer can also specialize functions and programmers can do too. Excessive specialization you get with templates always look beautiful in microbenchmarks but may not be ideal on a larger scale. There was a recent report analyzing the performance of Rust drivers vs C drivers and code bloat caused by monomorphization was an issue with the Rust things, and in my experience (also I do not have a reference) it is the same in C++.


> Optimizer can also specialize functions and programmers can do too

Yes, but not if you pass in void *. For libraries this matters. If you're both writing the producer and consumer then sure, you can do it manually.

> code bloat caused by monomorphization

This is true and a real problem, but I would argue in most scenarios extra codegen will be more performant than dynamic allocation + redirection. Because that's the alternative, like how swift or C# or Java do it.


Java does not monomorphize, it has no true generics - it's objects all the way down. It does, however, perform guarded devirtualization since all methods are virtual by default, so performance lives and dies by OpenJDK hotspot emitting guarded for fast, often multiple, dispatch as well as optimizing "megamorphic" callsites with vtable-ish dispatch (which is about the default cost of interface dispatch in .NET, somewhat slower than virtual dispatch).


Very interesting, thanks for sharing. Always neat to look into the inner workings of JVM implementations.


Of course it also works with void*.


I have written and worked on more than my fair share of Rust web servers, and the code is more than readable. This typically isn't the kind of Rust where you're managing lifetimes and type annotations so heavily.


> A better comparison would be with C++ or a similarly low-level language.

You probably want the apples-to-apples comparison but this looks an artificially limiting comparison; people are shilling, ahem, sorry, advocating for their languages in most areas, especially web / API servers. If somebody is making grandiose claims about their pet language then it's very fair to slap them with C++ or Rust or anything else that's actually mega ultra fast.

So there's no "better" comparison here. It's a fair game to compare everything to everything if people use all languages for the same kinds of tasks. And they do.


C# and Java are languages with very different performance ceilings and techniques available for memory management.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

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

Search: