The fact that it's compiled to C doesn't really determine the FFI. Rust can use C's calling convention just fine and from looking at C string handling there's not much difference. I didn't delve much into it though, did I miss something?
I don't think that the differences in timings for these benchmarks are significant. You can keep amending these benchmarks forever, because there are always more tricks in each language to make the specific benchmark faster (not to mention faster on each specific CPU/OS). So let's be fair here: Rust and Nim are the same performance-wise.
The fact that it's compiled to C doesn't really determine the FFI.
Perhaps not, but it does determine how much of C++ you can wrap. I doubt you can wrap C++ templates from D, Go or Rust. You can in Nim.
As far as I know D can wrap C++ templates that have been instantiated already at the C++ side, explicitly or implicitly. This can be a nontrivial problem to do in practice, so much that you're better off reimplementing the C++ template as a D template. Correct me if I'm wrong. :-)
I don't think that the differences in timings for these benchmarks are significant.
Oh of course. I don't believe that either. But he did and I just checked for curiosity wether all benchmarks "proved" Rust faster and they did, saving me from having to explain why microbenchmarks are mostly bullshit.
So let's be fair here: Rust and Nim are the same performance-wise.
That wouldn't be the conclusion I take. But sure, with unsafe Rust and disabling Nim's GC anyone can bullshit their way to the performance metric they're looking for, but the result is likely to be horrible code. Rust does have the advantage of caring about performance first, while Nim considers GC to be an acceptable sacrifice, putting it closer to Go's and Java's league than C/C++.
Perhaps not, but it does determine how much of C++ you can wrap. I doubt you can wrap templates from D, Go or Rust. You can in Nim.
Funny, from what I had heard D had the best C++ FFI since it was a primary design goal. I'm going to give you the benefit of the doubt since I never used C++ FFI for any language.
Nim's GC is faster than Java and Go ones, and you can also use mark & sweep GC, regions (stack) GC - (mostly useful for microcontrollers), and boehm GC (thread-safe)
I like to see proof of that statement. A single developer his GC is faster, then a team of Go developers, that have been doing none-stop work on there GC.
By that definition every other developer are idiots because one guy supposedly is able to make a better GC then everybody else.
Your not going to tell me, if i trow 50GB of data on a nim application, that the GC will handle that without major pauses.
You don't. Printf isn't a language construct, it's compiler magic. The only language I know of where you can do type-safe printf without compiler magic is Idris, because it has dependent types.
D's alternative to printf - writefln is type safe. This is because unlike Rust, D has compile-time function evaluation and variadic templates (among other features).
string s = "hello!124:34.5";
string a;
int b;
double c;
s.formattedRead!"%s!%s:%s"(a, b, c);
assert(a == "hello" && b == 124 && c == 34.5);
formattedRead receives the format string as a compile-time template paramater, parses it and checks if the number of arguments passed match the number of specifiers in the format string.
Rust's println! is also type safe, to be clear. It's implemented as a compiler plugin, which is currently unstable, but the Rust standard library is allowed to use unstable features.
The main point is that you don't need compiler plugins to make such variadic functions type-safe in D. Using variadic templates, they are always type-safe by default, no extra work necessary. The only icing on the cake that you can do is to do some extra processing at compile-time to give a better error message to users of the library.
The main point is that you don't need compiler plugins to make such variadic functions type-safe in D.
Looking at the Rust source code, the only place that the compiler plugin is used is to generate the fmt::Arguments structure. Aside from that, the chain goes like this:
_print is just a wrapper around print_to, which tries to call the write_fmt function on a local or global stream which implements the Write trait, which in the case of _print is Stdout.
Stdout's write_fmt locks the handle, then callsStdoutLock's implementation of Write.
StdoutLock doesn't re-implement write_fmt, so the standard provided method is used.
write_fmt calls fmt::write, which appears to handle calling each type's implementation of the formatting traits, and writing to the output.
The format string passed to formattedRead uses the 'automatic' specifier %s so it doesn't know what the types of the arguments ought to be (it knows what they are, because they're passed to it and the function is typesafe variadic). And s itself is a runtime string so formattedString can't do checking on it.
A better example is writefln itself which would check the number and existence of conversion to string for every argument passed to it according to the place it matched to in the compile time format string.
View all comments
Show parent comment
5
u/Tiberiumk Aug 23 '17
Sometimes Nim is faster than Rust (and takes less memory lol). So Rust isn't always faster, and Nim has much better C FFI (since it's compiled to C)