4 ms·
Initial binary size, like of a hello world, is a great indicator of how much abstraction the language has that youre also paying for. For example, java has to
by lionkor 3y ago
Initial binary size, like of a hello world, is a great indicator of how much abstraction the language has that youre also paying for.
For example, java has to set up a constants pool, parse it from the classfile, run init and cinit, resolve references, allocatea a frame, and so on, just to get to the entrypoint.
Compared to C without stdlib which needs to basically just run a few bytes to syscall write().
There are obviously massive advantages to Java for which these steps are needed, but you do pay for it.
- frfl 3y agoI'm not trying to be rude, but what does your comment have to do with the actual article linked. I suspect you're commenting based solely on the title? If you read the article it mentions 90% reduction if you remove the debug symbols from the rust std lib that get bundled in the final hello world binary. A conversation about Java's size and abstraction is quite irrelevant to the article.
- kelnos 3y agoThe article talks about how "hello world" binary size can be part of the first impression someone new to your language has. Java is a nice illustration of that. Rust probably isn't, because many of Rust's abstractions are zero-cost, so it's not as obvious a comparison.
- lionkor 3y agoMy comment is pretty unrelated to the content of the article, but more has to do with what others said here in the comments
- nindalf 3y agoIt’s funny, because your claim that it’s a great indicator is contradicted by the article we’re discussing. Rust was widely considered to be “only pay for what you use” despite having 4MB hello world programs. And now that it’s 400KB that continues to be true. So in this case, 4MB wasn’t a good indicator was it?
- lionkor 3y agoIts still a great indicator, its just that indicators dont mean very much sometimes.
- weinzierl 3y agoIt's funny that it was already considered be “only pay for what you use” when the binaries contained half of H. P. Lovecraft's œuvre. See issue #13871 https://github.com/rust-lang/rust/issues/13871 https://github.com/rust-lang/rust/issues/13871 I exaggerate, point is that we've come a long way and are still getting better. Different people look at different metrics and the more popular the language becomes the bigger the variety of metrics the come into focus.
- lifthrasiir 3y agoShould've used that as a ballast instead [1]. [1] https://web.archive.org/web/20230708052006/https://www.gamedeveloper.com/programming/dirty-coding-tricks https://web.archive.org/web/20230708052006/https://www.gamed... (search for "The Programming Antihero")
- rpigab 3y agoOut of curiosity, I looked at a basic hello world in C, and compiled it naively using gcc on Ubuntu, by default the executable produced was 15960 bytes, but when adding the -Os option (from the man page: "-Os Optimize for size") to enable many optimisation flags including code size, I was able to reduce it to 15968. #include <stdio.h> int main() { printf("Hello, World!"); return 0;} Of course, If I had read more than 3 words in the man page, the answer was easy to understand: "Os Optimize for size. -Os enables all -O2 optimizations except those that often increase code size", so you can't really get lower size than the default using only the optimization system, there's also "-finline-functions" included in -Os, but it won't help you in a Hello World.
- flohofwoe 3y agozig cc -Os -target x86_64-linux-musl hello.c -o hello ...which basically calls Clang under the hood, but comes with out-of-the-box cross-compilation support for Linux and MUSL creates a 5136 bytes executable.
- lifthrasiir 3y agoThis program is not same to the Rust version. A more faithful version, assuming glibc, would look like this: #include <stdio.h> #include <stdlib.h> #include <execinfo.h> #include <errno.h> void print_backtrace(void) { void *traces[50]; char **symbols; int num_traces, i; num_traces = backtrace(traces, sizeof(traces) / sizeof(*traces)); strings = backtrace_symbols(traces, num_traces); if (!strings) return; for (i = 0; i < num_traces; ++i) { fprintf("%d: %s\n", i + 1, strings[i]); } free(strings); } int main(void) { static const char FMT[] = "Hello, World!\n"; static int EXPECTED = (int) (sizeof(FMT) - 1); int ret = printf(FMT); if (ret < 0) { fprintf(stderr, "printf failed: %s\n", strerror(errno)); print_backtrace(); return 1; } if (ret != EXPECTED) { fprintf(stderr, "printf failed: only %d characters were written\n", ret); print_backtrace(); return 1; } return 0; } While this is still substantially different (for example, Rust's I/O buffering is different from C), this should be enough to demonstrate that this comparison is very unfair.
- ragnese 3y agoDebug symbols increase the binary size and don't really have anything to do with the abstraction level of the language. My understanding is that you also don't really "pay for" the debug symbols at runtime (until you generate a stack trace and need them). There could be some nuance that I'm missing there.
- edflsafoiewq 3y agoMore abstraction generally means more functions which means more debug symbols. For example, iterating over an array in Rust involves iterators, slices, options. There are lots of function calls, which all contribute debug info. In C, iterating over an array is a for loop and pointer arithmetic, no function calls, so much less debug info.
- ragnese 3y agoBut that's abstraction that you're actually using. The parent to my comment was implying that the debug symbols are an indication of abstraction that you're paying for whether you use it or not (in contradiction to the "zero cost abstraction" mantra/motto of C++ and Rust). You're perfectly welcome to just use a raw for loop with numeric indexes in Rust , in which case you wouldn't have those extra function calls for iterators, etc. Likewise, if you implemented an iterator abstraction in C, you'd end up paying a similar cost. So, that's not what the grandparent comment was talking about.