With C++, the template fans took over the language and overcomplicated it. Now you can't do anything in C++ without some template library. Even C++ enthusiasts admit that template programming is hard. It may even be a specialist skill that most C++ programmers do not have.
Rust picks up where C++ leaves off in that area. There's so much going on under the hood in templates that programmers are pushed into a ritual/taboo style of programming. (That's where you're taught to do something a certain way, but may not know why.)
It's really hard to kill off C.
I don't agree with this; using this logic, I would arrive to the conclusion that C is much harder to learn than assembly, as it has several levels of abstraction that assembly does not.
While I totally agree with C's longevity, Rust has something special going on.
You know that long bets website? I'd be happy to place a ten year bet with someone that Rust starts taking a big slice of C's pie. For kernel development, embedded systems, you name it. I'd be happy to qualify my bet with metrics based assertions, too.
The resource constraints are what make C essentially the optimal solution for those applications
Rust works fine without an OS. Some of the nice-to-have-stuff (inline assembly) aren't stable yet (I have been meaning to push for this with an rfc), but they'll get there.
fn insert_dup<K, V>(map: &mut BTreeMap<K, Vec<V>>, k: K, v: V)
where K: std::cmp::Ord,
{
map.entry(k).or_insert_with(Vec::new).push(v);
}
The same function in C++: template <typename K, typename V>
void insert_dup(std::map<K, std::vector<V> > &map, K k, V v) {
map[k].push_back(v);
}
The C++ code is shorter because if the "magic" operator[], otherwise they are roughly the same. Imo, templates are very useful because otherwise you can't make efficient statically typed containers.Rust generics are early-typechecked. You can't call a method on a generic parameter unless you have bounds saying that you can. And, similarly, you can't substitute type parameters in places where the bounds don't agree. This means that there are much clearer API boundaries (no more documentation snippets saying "T must have a method .foo()" or "specialization FooTrait<T> must exist") and cleaner error messages, but less metaprogramming power. Rust is hoping to make up for that loss of metaprogramming power elsewhere, but in a vacuum C++ templates are more powerful (though they have other downsides)
(FWIW you can index BTreeMap or hashmap as well with []; the difference is that [] will panic if it can't find the item. entry() gives a reference to the entry which you can check for emptyness and update before pushing if necessary. In C++ most things get implicitly initialized so that's not a problem)
I've not seen much use of SFINAE, just enough SFINAE is a "core" type that makes it infect everything.
C++ templates are unique in that they let you do a lot more than that; for example, you can have a different implementation for one specific type. std::vector<bool> is implemented differently from any other std::vector<K>. You can also have templates over values, not just types; so you could define some T such that T<5> differs from T<6> in some way.
I don't know rust; does it allow stuff like this?
That said, I am also looking forward to true type-level integers; they're needed for the truly proper translation of fixed size arrays in the Fuchsia IDL (fidl).
I think an optimal language would allow writing optimizations from within the language itself which would make it abstracted _but_ to also allow functions to be types themselves if you will and hold required compiler enforced time/space requirements.
Hmm. I've been seeing a LOT of posts and even presentations from folks claiming they've struggled with C/C++ and "systems" programming in general but have been able to take up Rust successfully. I'm with you on this; I've had long experience in C and have been dabbling in Rust for a few years and I think C is easier to understand, but unless I am to dismiss what many people have claimed as their own experience I realize that this is probably my internal bias.
The one thing that recurs among people that have trouble with C et al. are pointers. That doesn't surprise me; I did some tutoring in C in the late 90's and pointers are definitely a trouble spot for many new C programmers. To me it's all second nature and I see the *'s and &'s as simple operators doing simple, easily understood things, but I learned first hand that this is often _not_ easy for learners. While rust does have pointers they're are usually `hidden' and tend not to intrude in most Rust code, and I believe this is one reason some people and get on with Rust where they struggle with C.
On the desktop side of things, it will probably continue to be the favored systems language until universities start incorporating rust into their curriculum. Very few people have the motivation and incentive to learn a new language to accomplish something they can accomplish in a language they already know.
Seems to be a good place to ask: Is there a comparison out there of the complexity of a "typical" C compiler versus the Rust compiler? To check if it would be actually possible to port Rust to new platforms easily?
This is not to say that Rust will spread like wildfire, just that porting C isn't easier.
[0] https://en.wikipedia.org/wiki/ACM_International_Collegiate_P...
[1] https://icpc.baylor.edu/worldfinals/programming-environment
Once there isn't a dependancy on C-programs or code then C will be obsolete. Now the task comes to rewriting hundreds of thousands of hours of code to make it so that the rust backends for systems are up to spec with what's already layed down.
C is popular because a lot of stuff is written in it and it's the obvious choice due to the tooling for certian tasks.
The standard argument is that most of Rust's abstractions are, as much as possible, "zero cost".
However, while Rust's abstractions are very cheap, there is no such thing as a zero-cost abstraction. Why? Because abstractions hide information, and usually provide nicer interfaces than the underlying one. That changes the way you think. If, for example, your stdlib has a standard growable/shrinkable list type that's implemented as an LL under the hood, you'll likely use that structure whenever you need a list, even if you think it's a bad idea to use an LL in that context: it might not even occur to you to check how it's implemented.
Obviously, Rust doesn't do anything this braindead, but it still has abstractions, and those abstractions change the way you think, and may result in suboptimal programs as a result.
This isn't necessarily bad: I don't want to program in raw machine code all the time,and I doubt any of you do, either. But it is something to be aware of.
> C++ implementations obey the zero-overhead principle: What you don’t use, you don’t pay for [Stroustrup, 1994]. And further: What you do use, you couldn’t hand code any better. - Stroustrup
Everything has costs; that's engineering. But "I chose the wrong data-structure for my task" is not what the slogan is addressing.
>What you do use, you couldn’t hand code any better.
And that will never be true: if you know exactly as much about your usecase as the abstraction, than that might be possible, but that is almost never the case (which was my second point).
It is often true. Higher-level Rust code can and often does compile into the same assembly (or sometimes better!) than a lower-level construct. That's the entire premise of optimizing compilers. They're not perfect, but they do achieve this goal more often than "never".
See the Option comments above for one trivial example.
While it would probably be incorrect to claim zero cost across the board, there are abstractions that can be optimized to zero cost. For example, in Rust you don't use pointers that can be NULL, but the Option type which can be None. In the usual case, the optimizer translates this to the same assembly as using a raw pointer with NULL instead of None. So in the usual case, there is such a thing as zero-cost abstraction.
Again, why would this be a reason to prefer rust over c++?
If, given two situations
1. The the set containing compilers for language L is size 1, and that compiler works on multiple platforms; or
2. The set of compilers is > 1, but there exists at least one compiler in the set which is a) popular for use with language L b) not fully interoperable with the other compilers from the set that satisfy (a); then
situation 1 is the preferable one
Or to put it another way, nobody complains about code not working with compilers that don't exist.
Rust is in 1 of course. C++ is both in 2 and 3. In particular for C++, the compiler in 3 works on a strict superset of all the platforms supported by rust.
As you are free to support only this C++ compiler and ignore every other C++ compiler (you must not care about multiple implementations otherwise you wouldn't think that 1 is a good solution), it seems to me that 3 is strictly better than 1.
edit: I do concede that the existence of a popular but non-interoperable compiler[1] does fragment the community and it has been an issue in C++. Things are getting better though, and if rust becomes popular enough it might become an issue there as well.
[1] We all know which compiler I'm talking about.
Nightly Rust shouldn't be breaking your code. Use stable features, use repr(C) for stuff that's crossing the boundary (we sloppily didn't in some places, this did cause a breakage on a rust up, but that was our fault), and you should be good. Avoid unsafe-code-UB.
[1]: http://jakegoulding.com/blog/2016/01/02/rust-on-an-arduino-u...