6 ms·
Serious question: are D and Rust trying to be the same thing? I'm not asking whether or not their approaches are different, but whether or not they're trying
by omginternets 11y ago
Serious question: are D and Rust trying to be the same thing?
I'm not asking whether or not their approaches are different, but whether or not they're trying to solve the same problem(s). I get the sense that this is the case; they're both trying to be a "safe C(++)".
- CyberShadow 11y agoNo, but there is some overlap. Generally speaking, Rust puts safety above anything else. D is more pragmatic, expressive, and generally has better performance (e.g. bounds checking is optional). I think D is a better choice anywhere memory safety and deterministic memory management are not the primary concern.
- pcwalton 11y agoBounds checking is optional in Rust too. And I've never seen bounds checks show up in instruction-level profiling of Rust code, due to the way iterators work. Can you elaborate as to other ways Rust has worse performance?
- CyberShadow 11y ago> Bounds checking is optional in Rust too. Could've sworn I've read somewhere the Rust maintainers stated that Rust will never have a switch to disable bounds checking. Has this changed? > Can you elaborate as to other ways Rust has worse performance? I don't know of any other specifics, but benchmarks usually show D outperform Rust (and often enough, everything else), e.g.: https://togototo.wordpress.com/2013/07/23/benchmarking-level-generation-go-rust-haskell-and-d/ https://togototo.wordpress.com/2013/07/23/benchmarking-level... https://github.com/nsf/pnoise https://github.com/nsf/pnoise
- CyberShadow 11y agoHere is the relevant thread: https://mail.mozilla.org/pipermail/rust-dev/2014-March/009214.html https://mail.mozilla.org/pipermail/rust-dev/2014-March/00921... In some cases, bounds checking doesn't make sense, e.g. in video games running on consoles.
- pjmlp 11y ago> In some cases, bounds checking doesn't make sense, e.g. in video games running on consoles. As if it couldn't be used to exploit and pirate the games, get extra lifes, buy in-game items without paying, automate bots... "Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to--they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law." - C.A.R Hoare Turing Award speech, 1980
- CyberShadow 11y agoPretty much everyone in the video games industry is going to disagree with this. Performance is the primary concern there, period. Languages that reject such ideas in favor of others simply will not be used, given a choice. Consoles also only run signed code, enforce NX, and mprotect doesn't exist, so there is very little in what can be exploited. > automate bots... This has nothing to do with memory safety.
- pcwalton 11y agoAgain, bounds checking really doesn't show up in profiles. Iterators have none, and LLVM removes most of the ones that remain. It's really a non-issue.
- pjmlp 11y ago> Languages that reject such ideas in favor of others simply will not be used, given a choice. That is the key issue, "given a choice". I saw game developers being dragged into accepting C was replacing their beautiful Assembly, followed by game developers being dragged into accepting C++ was replacing their beautiful C. You can be pretty sure if tomorrow Sony, Apple, Nintendo, Google or Microsoft said "you must use language X", they would do it. So yeah, given the choice they can continue to lose money thanks to memory corruption exploits. Signed code and NX don't protect against memory corruption. One can use ROP to work around it.
- pcwalton 11y ago> Could've sworn I've read somewhere the Rust maintainers stated that Rust will never have a switch to disable bounds checking. Has this changed? Not having a switch to disable bounds checking is not the same as not being able to disable bounds checking. > I don't know of any other specifics, but benchmarks usually show D outperform Rust (and often enough, everything else), e.g.: It's been years since I saw those benchmarks. Those are benchmarks of the built-in library random number generator. Rust uses a more secure random number generator by default than most of the other languages, so it will go slower. If you really want to benchmark random number generation, pick a faster but less secure algorithm.
- CyberShadow 11y ago> Not having a switch to disable bounds checking is not the same as not being able to disable bounds checking. Not sure what you're getting at. Marking the entire program as unsafe is not realistic. Marking specific portions leaves a long tail of code that "rarely" runs, but still adds up. > Those are benchmarks of the built-in library random number generator. The levgen-benchmarks programs implement the XOR-shift RNG in both the Rust and D versions.
- deleted 11y ago[deleted]
- pcwalton 11y ago> but still adds up. No, it doesn't. Bounds checks in cold code don't matter (and there aren't many to begin with). Even bounds checks in hot code frequently don't matter. Have you profiled Rust code and found bounds checks to be a problem? > The levgen-benchmarks programs implement the XOR-shift RNG in both the Rust and D versions. Oh, I see that they changed it. Still, that benchmark is from 2013 and doesn't compile anymore. It predates unboxed closures and many other performance improvements. And 15% is in the "different register allocation decisions will affect the outcome" range, where comparisons are fairly meaningless. The fact that D and Rust beat C doesn't mean that they're faster than C.
- 11y ago
- dbaupp 11y agoRust has iterators which avoid the need for direct indexing in many uses of contiguous-memory storage, and hence avoid unnecessary bounds checks (just like D's ranges). When indexing is required, bounds checking can be disabled individually by indexing with `get_unchecked` (or `get_unchecked_mut`): http://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked http://doc.rust-lang.org/std/primitive.slice.html#method.get... In any case, when comparing language performance, it's generally good to avoid comparing backend performance, i.e. focus on the LLVM-based compilers in the pnoise benchmark. A GCC-based Rust compiler would almost certainly outperform the current LLVM-based one for that benchmark (as suggested by gcc vs. clang and gdc vs. ldc2). Of course, such a compiler doesn't currently exist, so if you care about getting your code to run as fast as possible right now, Rust isn't the best choice based on that benchmark, but Rust has several reasons that it's likely to outperform both C and D by default: - better aliasing information (than both C and D), so compilers can optimise more aggressively - lifetimes mean more aggressive stack allocation/ownership patterns can be used without risk (a bonus over C, and something that D solves via GC, which has its own upsides & downsides) - the type system has been designed to be particularly good at concurrency & parallelism, so again this can be used more aggressively and in more situations (e.g. libraries can expose interfaces that allow mutating data directly on the stack of other threads without risk of data races or dangling pointers)
- aldanor 11y agoRust iterators are a bit of a crutch IMO, until it's possible to return them unboxed; if you use them heavily you end up with types one paragraph long.
- dbaupp 11y agoYeah, it's annoying that one can't return them unboxed to be easily able to construct zero-overhead lazily-evaluated sequences, but that's entirely unrelated to their avoid-bounds-checks property. Instead of iterating over a range of indices and indexing, use the slice iterator, it's basically a drop-in replacement. The former can either be done with a manual loop & addition (which is not at all lazy and definitely can't be returned, i.e. Rust's current iterators are strictly more flexible), or it is done with the Range iterator. The two lazy forms are basically the same: let v: &[T] = ...; let x: iter::Map<ops::Range<usize>, _> = (0..n).map(|i| { let elem = &v[i]; // do stuff }) let y: iter::Map<slice::Iter<T>, _> = v.iter().map(|elem| { // do stuff });
- yokohummer7 11y ago> D is more pragmatic Being pragmatic is a very questionable claim. Its exact meaning varies from time to time, and a property that a certain people consider to be pragmatic can be considered to be not pragmatic by another people. It's mostly meaningless. For example, for embedded devices D is a no-go from the beginning. I'm not just saying the reliance on GC. D has a few ridiculous behavior that may cost significantly on the low resource devices, such as http://forum.dlang.org/thread/mr6bl7$26f5$1@digitalmars.com http://forum.dlang.org/thread/mr6bl7$26f5$1@digitalmars.com D is never pragmatic in this area. But of course, D may be pragmatic in other areas. > expressive D and Rust have different kinds of expressiveness. While D has much better compile-time metaprogramming, how do you express affine type in D? In Rust affine type is very fundamental and we can utilize it to define the exact meaning of our programs. > and generally has better performance (e.g. bounds checking is optional). What? How can a GC'ed language be faster than a non-GC'ed language? Besides simple numeric evaluation, D is generally more heap-allocation-heavy than Rust, so it can never beat Rust. After all, there's no point in Rust if it's slower than a GC'ed language. The benchmarks you linked are questionable too, as their results say D is faster than C. Are you really sure D can outperform C in general cases?
- rpedela 11y ago> How can a GC'ed language be faster than a non-GC'ed language? Besides simple numeric evaluation, D is generally more heap-allocation-heavy than Rust, so it can never beat Rust. I would be interested in benchmarks showing that. Do you have any?
- deleted 11y ago[deleted]
- yokohummer7 11y agoSorry, I don't have specific numbers. I was saying generally for all GC'ed languages.
- qznc 11y agoD has lots of tools to avoid heap allocation. There is no reason why D should use more heap allocations than Rust. A GC might only encourage you to use more heap allocations.
- wyldfire 11y agoIIRC D has a GC that you can opt-out of but in practice it's difficult to use its standard library when you do. I'm just repeating a critique that I read, I haven't evaluated them against one another. Having a GC excludes you from some programming domains -- well controlled latency, bootstrapping/operating systems.
- acehreli 11y agoThe GC situation is getting better: - The language has the @nogc attribute to ensure at compile time that the GC is not used in a function or an entire module. - The number of standard library functions that have the @nogc attribute is increasing by the minute. :) - There is some effort to port Sociomantic's proprietary multi-threaded GC to D (theirs was written for D1).
- pjmlp 11y ago> bootstrapping/operating systems. Oberon, Modula-3, Singularity designers don't share the same opinion
- CyberShadow 11y ago> Having a GC excludes you from some programming domains -- well controlled latency, bootstrapping/operating systems. Even without the GC, D is still a good "better-C" language. The GC didn't stop people writing bare-metal / operating system kernels in D: https://github.com/JinShil/D_Runtime_ARM_Cortex-M_study/wiki/1.1---Hello,-World! https://github.com/xomboverlord/xomb
- pcwalton 11y agoRust is interested in zero-overhead memory safety and data race freedom, while D doesn't seem to be. From a design perspective, that's a major difference. Note that the safety benefits must of course be weighed against the number of moving parts in the type system you desire for your project.
- CyberShadow 11y ago> Rust is interested in zero-overhead memory safety and data race freedom, while D doesn't seem to be. Of course D is interested in those concepts, simply not to the extent that Rust is. For example, D has: - pure functions - opt-in strict memory safety (@safe) - sealed references (http://wiki.dlang.org/DIP25 http://wiki.dlang.org/DIP25) - transitive immutability - shared types
- pcwalton 11y agoSealed references and transitive immutability are interesting, but they aren't nearly enough to allow most programs to be expressed without GC. You really need (a) the ability to store references in structures; (b) the ability to have multiple lifetimes per function; (c) propagation of immutability through heap objects and unique loan paths.