There are many new C ripoffs, but nobody seems to acknowledge Cyclone (https://cyclone.thelanguage.org/) which is a lot older. It was even backed by a corporation (AT&T), but never succeeded. I wonder why.
> Cyclone is no longer supported; the core research project has finished and the developers have moved on to other things. (Several of Cyclone's ideas have made their way into Rust.) Cyclone's code can be made to work with some effort, but it will not build out of the box on modern (64 bit) platforms).
> Many variations [he's talking about Rust] that seemed like they ought to run the same speed or faster turned out slower, often much slower. By contrast, in C++ it was surprisingly difficult to discover a way to express the same operations differently and get a different run time.
This is an insidious pitfall that may earn Rust the "slow" label, akin to what happened to Common Lisp.
> This is an insidious pitfall that may earn Rust the "slow" label, akin to what happened to Common Lisp.
This doesn't match my experience at all with Rust, for what it's worth. Not having copy constructors makes up for any difference in that regard: in C++ it's way too easy to accidentally deep copy a vector and the entire object graph underneath it--all it takes is "auto a = b" as opposed to "auto& a = b"--with very bad performance consequences. Rust, on the other hand, doesn't let you deep copy unless you explicitly ask it to.
When I went back to C++ after learning Rust and used a vector again, I realized this and it hit me like a brick. I used to program in C++ before, so it wasn't like I didn't know this, but it was something rather unremarkable to me. Then I go back to C++ and throw vectors around willy-nilly and stuff works. Huh, I thought, this feels strange, I wonder how C++ accomplishes this without a garbage collector or ownership. Then it hit me -- it deep copies All The Things. Again, I already knew this, but I hadn't ever thought about it much. But the change in perspective made it stick out like a sore thumb.
In Rust, if you want a deep copy you (IIRC) implement the Clone trait, which allows you to explicitly clone everything. Many collections in the standard library already implement this, so you get it by default :).
Edit: I should point out that deep copies can only be explicit in Rust -- there's no implicit deep copy AFAIK.
The Qt C++ library does some neat tricks to avoid copying. For example its vector class (like nearly all of its container/value classes) overloads the "=" operator to perform shallow copies. So even though default behavior in C++ is to deep copy, it's possible to override.
Qt even takes it further by providing automatic copy-on-write. Methods that read data operate on the shared copy. Methods that change data cause the object to deep copy and detach first. This allows writing programs using values rather than references, while retaining the performance of references.
Not just that, but there's a lot of optimizations that would be nice, but we haven't implemented yet. (Though some of these will end up being more to help with compile times than runtime performance, though)
LLVM is great, and it's the reason why Rust is able to match C++ in performance on this workload, but it's not a magic-optimizer-of-everything: it's tuned to C and C++. We have added a couple of Rust-specific optimizations to it, but not a whole lot.
I suspect what the author was seeing was random performance differentials between iterators and loops, which often boils down to little missed optimizations in LLVM. If you find them, please file them in the Rust bug tracker--we've fixed many of them and will continue to do so in the future!
Note that when MIR lands, progress on which is well underway, we'll have the ability to do optimizations at the Rust IR level in addition to the LLVM level. This should make it easier to do these kinds of things.
As I understand it, there are a number of potential optimizations based on Rust's implicit understanding of the lifetime of a memory region. LLVM doesn't know about those because they can't be represented in the IR. Last I heard, any kind of optimization work based on the extra information rustc has is waiting for the compiler refactor that's currently underway.
I dunno, it's very easy for me to express things differently in C++ and get a different runtime. It's easy enough for a bunch of C++ programmers writing needlessly slow code whom I've known. It must be equally easy for the author. The reason he doesn't ought to be vast experience with C++, so that he doesn't try obviously dumb things (as in things that malloc a ton of stuff needlessly, etc.), whereas his Rust experience is necessarily smaller. I think you need quite a bit of experience to declare that, well, experience just doesn't help because the performance model of this thing is weird!
Adding just a single tick mark to make a big difference in performance is one of many areas in Haskell that make performance-minded development a pain. With these high-level languages, you really have to understand the implementation of the language to get anything fast written.
When I'm bored I pick a random section and read it. I was really fascinated by the section on sorting networks for example.
The real gems are the exercises and answers to them; there's at least as much useful/applicable stuff as in the main text. I tried to solve them, but found myself unable to proceed with them if difficulty was > 20, even if I understood the concepts. I have no idea on how to attack them. (Even non-mathematical ones.)
IMHO, TAOCP needs "Volume 0" which would teach you problem solving in this particular domain. (No, "Concrete mathematics" is not it. That book is, IMHO, awful: many problems depend on having tricks up your sleeve.)
Any tips on how to approach exercises which seemingly don't have a lot to do with the preceding text?
In my previous job we were evaluating HDF5 for implementing a data-store a couple of years ago. We had some strict requirements about data corruption (e.g., if the program crashes amid a write operation in another thread, the old data must be left intact and readable), as well as multithreaded access. HDF5 supports parallelism from distinct programs, but its multithreaded story was (is?) very weak.
I ended up designing a transactional file format (a kind of log-structured file system with data versioning and garbage collection, all stored in a single file) from scratch to match our requirements. Works flawlessly with terabytes of data.
No and no. Strictly proprietary technology which gives a real competitive advantage. Fun thing is, if you choose your data structures wisely, it's not even that hard to write; it ended up being under 2k lines of C++ code.
GC was offline though; it was performed at the time the container was "upgraded" from RO to RW access. I don't think it'd be difficult to make it online, but there was no need for that.
Right. I spend less than half of my income on neccessities (food, rent, etc. -- this I split with my partner) and recently I've found myself telling people that time is my most limited resource. So in the past couple of years I've been very conscious about allocating my free time.
When I quit may last job I wanted to trade the notice period with unpaid vacation, but it was no-go. :(
Nice to see that C++ is picking up speed after C++11. In my previous job I had to work with "legacy" C++, but now I'm working with "modern" C++. The difference is huge. C++11 features allow me to do more with less headache and I'm more confident in code correctness.
> I'm not sure that's the best example. In that case, the knowledge that the 'array' global never has its address taken allows you to perform the optimization.
Separate translation units. For this to work, you'd need to postpone all optimizations to the link stage. Even then you're not safe, because you may be producing a dynamic library and the program loading it can take the address of an object by dlsym().