Reading the #RustLang book is a treat. So much stuff that causes headaches and uncertainty in other languages is just handled in the core language in Rust.

@annika the book really is great, much better than what most other languages offer, but one thing put me right off using Rust. Going by the book I wrote the simple Fibonacci function. It's 4 MB on my system. 4 MB to print 3 Fib numbers.

I wrote nearly the same code in #Nim and it's 850KB statically linked against libc (220KB dynamically linked). In debug mode!

Follow

@kungtotte @annika You can still reduce the size of the binary using gcc's magic (I never remember how to do it), but it's always quite big comparing with the binaries C generates.

@ekaitz_zarraga @annika yeah you can jump through hoops to get there (you can with Nim too), but Nim is already good enough out of the box for 90% of cases that you don't have to do that. It also makes source distribution easier as people can compile using default-ish settings on their system and not get massively bloated binaries.

nim c -d:release --opt:size --passL:static makes for a size optimized statically linked release build. Not hard to remember.

@kungtotte @ekaitz_zarraga @annika I think you forgot to `strip` it, of course it weighs way less without debuginfo for the whole stdlib:

$ cat fib.rs
fn main() {
let mut a = 0;
let mut b = 1;

for _ in 0..10 {
println!("{}", b);
let c = b;
b += a;
a = c;
}
}
$ rustup run nightly rustc fib.rs
$ du -sh fib
2.4M fib
$ strip fib
$ du -sh fib
196K fib

@bugaevc @ekaitz_zarraga @annika that's what I mean about jumping through hoops. It's too long for a toot but here's a comparison using identical code for both languages and what it produces.

Nim dynamically links against glibc but it's my understanding that Rust does that too by default? Correct me if I'm wrong.

Even statically linked against glibc in debug mode the non-stripped Nim binary is only ~twice the size of the stripped rust binary...

gist.github.com/kungtotte/07c9

@bugaevc @ekaitz_zarraga @annika my point is this: with a 112K debug-symbol-filled binary I don't have to do anything more with Nim. It's done, ship it and let your users rejoice that they can debug their shiny but useless Fibonacci app. Even statically linked it's less than 1 MB with debug symbols.

I prefer Nim in this regard.

What filesize you can ultimately reach by jumping through hoops is less important than sane defaults.

@kungtotte @ekaitz_zarraga @annika true, and I would also like to see Rust produce smaller binary sizes right out of the box (they're working on it!), but stripping the binary is standard practice, not jumping through hoops, and it gets you down to an acceptable size. And well, Rust is explicitly optimizing for performance over binary sizes when possible (e.g. aggressive inlining and monomorphization), so no wonder its binaries are larger in the end.

@bugaevc @ekaitz_zarraga @annika with default compilation settings, a stripped rust binary is still four times the size of a non-stripped Nim binary with default settings. It's also comparable in performance since it compiles to C first.

If these proportions hold for real programs then Rust has a problem.

@kungtotte @ekaitz_zarraga @annika that's... not how this works.

Compiling to C means that there's no interpretation involved at runtime (good), but it says nothing about what kind of code it compiles to — in particular, does it use GC? Does it pervasively box everything non-primitive onto the heap? (yes and yes for Nim, with asterisks).

@kungtotte @ekaitz_zarraga @annika

Differently designed libraries even for the same language can have dramatic performance difference, and Rust ecosystem is all about enabling maximum performance where possible. Don't know if you've seen this post, but it's a great example of this approach: aturon.github.io/blog/2016/09/

@kungtotte @ekaitz_zarraga @annika

Binary size wise, these hello world/Fibonacci examples are basically the baseline, they contain all the ELF/Mach-O/PE structure and the statically linked Rust/Nim stdlibs — your actual Fibonacci code compiles down to a few assembly instructions, and the rest is boilerplate. Try compiling a sample that has 10x as much code, I'm sure your binary size will be less than double of the Fibonacci baseline for both Rust and Nim.

@bugaevc @ekaitz_zarraga @annika I don't know how they compare internally but I just did this on my system:

% du -h `which nim`
2.0M
% du -h `which rustc`
15M

Stripping brings them to 1.7M and 9.3M respectively.

You can try and sell the safety and performance of Rust all you want, but you can't escape the fact that they have a major issue with binary sizes.

@kungtotte @ekaitz_zarraga @annika indeed, they are very different compilers, there's little sense in comparing their sizes directly. In particular, rustc bundles its own copy of LLVM (which is not even written in Rust, btw), and somehow /lib64/libLLVM-7.so (the shared system one that clang uses) is 58 MB on my system, so 15 MB for rustc actually sounds small.

@kungtotte @ekaitz_zarraga @annika But yes, as I've already said Rust favors performance over, and at the cost of, binary sizes (though that doesn't mean binary sizes shouldn't be optimized).

@charlag @bugaevc @kungtotte @ekaitz_zarraga @annika they switched to using the system's native allocator by default - which was possible now because they've implemented a method of choosing a custom allocator. So you can now opt-in to using jemalloc, or possibly even write your own allocater.

Sign in to participate in the conversation
Mastodon

Server run by the main developers of the project 🐘 It is not focused on any particular niche interest - everyone is welcome as long as you follow our code of conduct!