I'm talking about the stability of the language feature set and the amount of change it's undergoing, rather than the quality of the implementation or anything of that sort.
While it's good to see the language evolving and improving, this type of churn also means it isn't very practical to use.
For example, some experimental Rust code I wrote a mere 6 to 8 months ago is now basically unusable with recent versions of Rust due to language functionality changes, syntax changes, and library changes.
I keep hoping that it'll start to stabilize, even just on a feature set and standard library that may not be perfect, but will at least be usable for longer than a few months. Yet this doesn't seem to be happening. This lack of stability will start to significantly hurt its adoption at some point.
Go has taken a better approach, in my opinion. It isn't perfect, and it's lacking some important functionality, but at least there's a version that's usable, well-supported, and usable well into the future, even if the language does continue to evolve in incompatible ways.
That's right. We never claimed otherwise.
> I keep hoping that it'll start to stabilize, even just on a feature set and standard library that may not be perfect, but will at least be usable for longer than a few months. Yet this doesn't seem to be happening. This lack of stability will start to significantly hurt its adoption at some point.
It is absolutely our intention to create a backwards-compatible version of Rust soon. We've created a milestone to tag issues related to this: https://github.com/mozilla/rust/issues?milestone=13&state=op...
> Go has taken a better approach, in my opinion. It isn't perfect, and it's lacking some important functionality, but at least there's a version that's usable, well-supported, and usable well into the future, even if the language does continue to evolve in incompatible ways.
Go also started earlier and is less ambitious of a language (and I think everyone on the Go team would agree with that statement). It has nothing like the borrow check that has required delicate care in design, and research in every sense of the word, to create something usable. Earlier versions of Rust were not really usable for what we want to use it for—Servo—and there is no point sticking to a language that isn't the language we need. Even current Rust is not ideal for Servo (lack of custom smart pointers, most notably) and that's why we continue to evolve it. Nevertheless, we have a good idea of the feature set we want and the language is stabilizing.
But I still give Rust a pass on this for the time being. Rust is a younger language than Go (Rust is not yet at version 1, while Go is at 1.1.1), and Rust supports far more compile-time features.
This may even be more harmful than no documentation at all, especially for people new to the language.
While this is an issue for other languages, I've found it to be far more severe with Rust.
Furthermore, Rust is quite ambitious. Getting lifetimes and the borrow check to work right is hard and involved research in all senses of the word; read the borrow check source code sometime. We did not just change things because we felt like it.
Rust is starting to settle down, and once it has settled, it will be very stable. In particular, the 0.6 release was a huge breaking one, and 0.7 was less so. As it approaches 1.0, things should calm down quite a bit.
That's exactly what the death of a promising language looks like.
Those people should just go elsewhere, there are enough worse-is-better languages to pick from without dragging down yet another one.
Any further 1.x releases should clearly try to avoid incompatibility as much as possible. Anyone seriously using a programming language does require a relatively high degree of stability with respect to language changes, library changes, and so forth.
But that in no way means that there can't be work done on a 2.x release that does introduce incompatibilities in an effort to improve the language and any standard libraries it may offer.
This situation is much more about controlling change, rather than preventing it outright.
The most realistic way to address your criticism would just to have been to keep the language a secret until it's mostly stable. This is what most other companies do (for example, this is what Google did with Go). But then you couldn't use it at all.
I have read a bit about this for Haskell. What in Rust facilitates the same, that is absent from Go (or C, C++) ?
C++ functionality like references and smart pointers make pointer nullability and memory safety irrelevant, or at least much, much less of an issue than in C or older C++ code.
RAII significantly helps with lifetime management of all sorts of resources, from memory to database connections to files.
There are various collection libraries for C++ that make out-of-bounds accesses a non-issue, at a very minimal cost.
Likewise, it's quite easy in almost all cases to avoid using unsafe casts and other behavior that may cause problems, when taking a more modern approach to C++.
With a small amount of discipline, C++ of today can be much different than C++ of the 1980s or 1990s. Many of the pitfalls of that era can be avoided with remarkably little effort, especially when using C++11 and modern implementations. Yet it still easily gives you access to very powerful functionality for those rare cases when it is needed. This is much harder to do in many other, more modern languages.
This is dangerously incorrect. Having spent much of my career finding new and exciting ways to break modern idiomatic C++'s memory safety, I can confidently say that no reasonable subset of C++ is memory safe.
Try to solve iterator invalidation, for example.
> With a small amount of discipline,
I would just like to point out that when dynamic language advocates suggest that 'with a small amount of discipline, you can write reasonably safe dynamic code' and you laugh them off with comments about how static typing saves you from errors at compile time.
The same is true with languages like Rust or Haskell; you don't need the discipline, the compiler catches such things for you.
In C++, it's mostly just a matter of understanding the language features you're using, and then avoiding ones that can be harmful in some cases, often in favor of much safer alternative approaches.
The C++ compiler will still catch many other types of problems at compile time that wouldn't necessarily be noticed (assuming they even are noticed by the developer(s)) until runtime when using a dynamic language. The safety net offered by the C++ compiler may not be cast as wide as that of Rust or Haskell, but it's still there, and it does catch many common issues.
And I think it's wrong to say that Rust and Haskell don't require discipline; they do. It's still easy to write inefficient or unmaintainable code in those languages, for example. You still need to know what you're doing, and how to use the functionality that they offer, in order to avoid problems like that.
Now, the discipline needed when using a dynamic language not only includes the discipline needed when using C++ (that is, "don't do stupid stuff"), but it also includes not making trivial mistakes like typos, or missing some changes when refactoring, and so on. Much, much more discipline is needed when writing code in dynamic languages.
That is the kind of discipline that can be automated away to a very large extent, however. Personally, I do think it's silly and wasteful to willingly take on responsibility for ensuring that sort of discipline for anything but the smallest scripts. So, yes, I will speak out against it and those who suggest it's acceptable, especially in larger systems.
The number of security bugs that every large C++ codebase sees suggests otherwise. C++ is neither safe in practice nor in theory. (I can come up with many ways in which modern idiomatic C++ can be broken, often in an exploitable manner.)
Yes, but the subject was correctness and the discussion was about the fact that these languages makes it easier to write correct code than e.g. Go or C++.